反射的性能问题与优化
面试官问:"反射有什么性能问题?如何优化?"
候选人小冯答:"反射调用比普通方法调用慢很多,可以缓存 Method 对象来优化。"
面试官追问:"反射慢的原因是什么?能具体量化吗?"
小冯说:"大概慢个几倍?"
面试官又问:"除了缓存 Method 对象,还有其他优化方式吗?"
小冯说不出来了。
【面试官心理】 这道题考的是候选人对 JVM 底层机制的理解程度。能说出"MethodHandle"、"Inflation 机制"、"JIT 内联失效"的候选人,是真正研究过这个问题的。
一、反射的性能开销量化 🔴
1.1 性能对比(真实数据)
1.2 性能开销的来源
二、JDK 反射的 Inflation 机制 🔴
2.1 JDK 8 及之前的 Inflation
inflationThreshold = 15(可通过 -Djdk.invoke.reflection.Threshold=N 修改)
2.2 JDK 17+ 的改进
JDK 17 移除了 Inflation 机制,简化了反射调用路径,性能提升约 30%:
三、优化策略 🔴
3.1 缓存 Method/Field 对象
Spring、MyBatis、Hibernate 内部都大量使用了 Method/Field 缓存。Spring 的 CachedIntrospectionResults 就是专门做这个的。
3.2 使用 MethodHandle 替代反射
3.3 设置 setAccessible 的方式
3.4 使用 LambdaMetafactory 内联优化
四、Spring 框架的反射优化 🔴
4.1 CachedIntrospectionResults
4.2 Spring Boot 的 Optimized
Spring Boot 2.x 之后,大量使用 reflection-pbo(Reflection Based Property Wrapper)进行反射优化,减少反射调用次数。
五、生产中的反思使用场景 🔴
5.1 序列化/反序列化
5.2 通用 CRUD 框架
在高频调用场景(每秒数万次反射调用),即使做了所有优化,反射仍然可能是性能瓶颈。MySQL JDBC driver 在 8.0 版本后将 PreparedStatement 的反射调用改为直接类型化调用,性能提升显著。
六、追问升级
面试官:"Unsafe.getObject() 能绕过反射性能开销吗?"
Unsafe 确实更快,但:
- 安全性:Unsafe 可以访问任意内存地址,是安全漏洞来源
- 兼容性:JDK 9+ 模块系统限制了对 Unsafe 的访问
- 正确性:错误的 offset 会导致 JVM 崩溃
【面试官心理】 能说出 Unsafe 并讨论其限制的候选人,说明对 Java 底层有一定研究。但要注意,说 Unsafe 是为了"优化"而不是为了"破解"才是正确的角度。