为什么VisualVM采样器不能提供关于CPU负载(方法时间执行)的完整信息?

17
问题是:VisualVM采样器按时间显示调用树。对于某些方法,采样器仅显示“自身时间”,因此我无法看到是什么使该方法变慢。这里有一个示例。如何增加分析的深度?

该链接已过期并无效,是否有可能将示例嵌入问题中? - ADTC
2个回答

47

很不幸,由于许多原因,取样分析器在深度分析方面相当有限:

  • 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.

避免这些弱点的唯一方法是使用仪器化分析程序而非采样分析程序。仪器化分析程序,例如VisualVM中“Profiler”选项卡提供的程序,本质上记录所选代码中每个方法的进入和退出。不幸的是,仪器化分析程序对受分析代码产生了相当大的影响:
  • 它们在每个方法周围插入监控代码,这完全改变了JVM对方法的处理方式。由于额外的代码,即使是简单的字段getter/setter方法也可能无法再被内联,因此会扭曲任何结果。分析程序通常会尝试解决这些问题,但并不总是成功。

  • 它们会导致受分析代码严重减速,因此完全不适合用于监视完整应用程序。

出于这些原因,仪器化分析程序通常适用于使用其他方法(例如采样分析程序)已经确定的热点分析。通过仅对选定的类和/或方法进行仪器化,可以将分析的副作用限制在应用程序的特定部分。

1

这个例子没有错。 看起来 updateInfoInDirection() 调用了 new SequenceInfo()SequenceInfo.next()。 'Self time' 意味着时间花费在方法代码本身上(当线程采样时,updateInfoInDirection() 方法位于堆栈底部)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接