我广泛使用jProfiler,它是一个很棒的工具,但我想知道jProfiler如何处理JIT编译的影响。
即时编译实际上是一种相当古老的技术,已被HotSpot自适应优化器所取代。JIT盲目地将Java字节码中的每个方法编译为本机代码,并且可能(也可能不)能够很好地优化它。
但是,自适应优化器会查看代码的当前运行方式,并仅优化最常执行的代码。由于优化程序知道代码的使用方式,因此优化程序可以并且能够更好地进行内联、分支预测、锁粗化、循环展开等方法。
例如,我是否能够观察到方法内联?如果一个方法是内联的,那么它在快照中根本不可见,或者jProfiler仍然能够计算其执行时间吗?
JProfiler不会报告哪些方法已被内联;但是,它将很乐意报告它们的调用,即使编译器将它们内联到另一个方法中也是如此。
如何?好吧,在编译期间,编译器在本机代码中划分了方法边界。这对于 JVM 在发生异常或错误时能够重建堆栈跟踪至关重要。当对 JVM 进行采样时,JVM 使用执行线程的堆栈跟踪进行响应,因此可以准确报告当前方法,即使它是内联的。
同样,没有副作用并且可以完全优化的方法也不会显示在jProfiler中。这是正确的吗?
你几乎是对的。没有副作用或计算返回值或调用另一个可能副作用的方法几乎完全被优化,但是JVM中有一个化石残留物记录了该方法将被调用。边际开销非常小,但具有以下有趣的特征:
- 采样时,此方法在采样时不太可能出现在堆栈上,因此 jProfiler(或其他采样分析器)很可能不会检测到此方法。
- 检测时,探查器跟踪所有方法调用,并将检测方法调用。如上所述,总成本将非常小。
本文介绍了采样与检测的区别。