我遇到了这样的情况:我看不到某些方法调用没有被VisualVM应用程序记录下来。想找出原因,我找到了这个SO上的答案。第三点提到了采样方法可能存在潜在问题(这似乎是唯一一个选项,因为我正在进行远程分析)。它提到了代码中的安全点和代码本身对安全点轮询的问题。这些术语是什么意思?
关于Java采样分析工具的不准确性问题及其与安全点的关系,在评估Java分析器的准确性(PLDI'10)中有很好的讨论。
基本上,由于采样发生在安全点期间,因此Java分析器可能会产生不准确的结果。由于编译器可以修改安全点的出现,因此分析器可能永远不会对某些方法进行采样。因此,分析器被安排记录代码的采样(时间间隔到了),但必须等待安全点的出现。由于编译器会移动安全点,所以理想情况下应该采样的方法从未被观察到。
正如先前的答案所解释的那样,安全点是代码中的事件或位置,编译器在其中断开执行以执行一些内部VM代码(例如GC)。
安全点轮询是实现安全点或安全点触发器的一种方法。这意味着在正在执行的代码中,您定期检查标志以查看是否需要执行安全点执行,如果是(由于例如GC触发器),则线程被中断并执行安全点。请参见GC安全点(或安全区域)。
这篇博客文章讨论了安全点。 基本上,它们是代码中允许GC、堆栈跟踪等中断的点。
该文章还说,由于安全点会延迟堆栈采样,因此可能无法在您希望它们出现的位置出现,这是一个问题。
在我看来,这只是一个小问题。 之所以进行堆栈采样(而不仅仅是程序计数器采样),是为了展示导致当前状态的所有调用站点,因为它们很可能是比程序计数器执行更缓慢的重要源。 (如果有的话。您可能正在进行I/O,在那里PC是无意义的,但是调用站点仍然同样重要。) 如果堆栈采样必须等待几个周期才能到达安全点,那么所有这意味着它发生在一段指令块的末尾,而不是中间。 如果您检查样本,仍然可以很好地了解发生了什么。
我希望分析器编写者们意识到他们不需要过多关注细节。 更重要的是不要错过大问题。