很不幸,由于许多原因,取样分析器在深度分析方面相当有限:
Samplers are limited by the sampling period: For example, VisualVM currently has a minimum sampling period of 20ms. Modern processors can execute several million instructions in that time - certainly more than enough to call several short methods and return from them.
While an obvious solution would be to decrease the sampling period, this would also increase the impact of the profiler on your application, presenting a nice example of the uncertainty principle.
Samplers are easily confused by inline code: Both the JVM and any decent compiler will inline trivial and/or frequently-called methods, thus incorporating their code in the code of their caller. Sampling profilers have no way to tell which parts of each method actually belong to it and which belong to inline calls.
In the case of VisualVM Self time actually includes the execution time of both the method and any inlined code.
Samplers can get confused by an advanced VM: For example, in modern JVM implementations methods do not have a stable representation. Imagine for example the following method:
void A() {
...
B();
...
}
When the JVM starts B()
is interpreted straight from the bytecode, thus taking quite a bit of time which makes it visible to the sampler. Then, after a while the JVM decides that B()
is a good candidate for optimization and compiles it to native code, thus making it much faster. And after yet another while, the JVM might decide to inline the call to B()
, incorporating its code in A()
.
At best, a sampling profiler will show the cost of those first runs and then the cost of any subsequent runs will be included in the time spent by the caller. This, unfortunately, can confuse an inexperienced developer into underestimating the cost of the method that was inlined.
At worst, that cost may be assigned to a sibling call, rather than the caller. For example, I am currently profiling an application using VisualVM, where a hotspot seems to be the ArrayList.size()
method. In my Java implementation that method is a simple field getter that any JVM should quickly inline. Yet the profiler shows it as a major time consumer, completely ignoring a bunch of nearby HashMap
calls that are obviously far more expensive.
它们在每个方法周围插入监控代码,这完全改变了JVM对方法的处理方式。由于额外的代码,即使是简单的字段getter/setter方法也可能无法再被内联,因此会扭曲任何结果。分析程序通常会尝试解决这些问题,但并不总是成功。
它们会导致受分析代码严重减速,因此完全不适合用于监视完整应用程序。
这个例子没有错。 看起来 updateInfoInDirection()
调用了 new SequenceInfo()
和 SequenceInfo.next()
。 'Self time' 意味着时间花费在方法代码本身上(当线程采样时,updateInfoInDirection()
方法位于堆栈底部)。