为什么 VisualVM Sampler 不提供有关 CPU 负载(方法时间执行)的完整信息? [英] Why VisualVM Sampler does not provide full information about CPU load (method time execution)?

查看:76
本文介绍了为什么 VisualVM Sampler 不提供有关 CPU 负载(方法时间执行)的完整信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题是:VisualVM 采样器按时间显示调用树.对于某些方法,采样器仅显示自我时间",因此我看不出是什么使此方法变慢.这是一个例子.
如何增加分析的深度?

The problem is: VisualVM sampler shows call tree by time. For some method sampler shows only "Self time" so I can't see what makes this method slow. Here is an example.
How can I increase the depth of profiling?

推荐答案

不幸的是,由于多种原因,采样分析器在深入分析时相当有限:

Unfortunately sampling profilers are rather limited when it comes down to in-depth profiling due to a number of reasons:

  • 采样器受到采样周期的限制:例如,VisualVM 目前的最小采样周期为 20 毫秒.现代处理器可以在这段时间内执行数百万条指令——当然足以调用几个短方法并从中返回.

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

采样器很容易被内联代码混淆: JVM 和任何合适的编译器都会内联琐碎和/或频繁调用的方法,从而将它们的代码合并到调用者的代码中.采样分析器无法分辨每个方法的哪些部分实际上属于它,哪些属于内联调用.

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.

在 VisualVM 的情况下,自我时间实际上包括方法任何内联代码的执行时间.

In the case of VisualVM Self time actually includes the execution time of both the method and any inlined code.

采样器可能会被高级 VM 弄糊涂:例如,在现代 JVM 实现中,方法没有稳定的表示.例如,想象一下以下方法:

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();
    ...
}

当 JVM 启动时 B() 直接从字节码解释,因此需要相当多的时间使其对采样器可见.然后,JVM 会在一段时间后决定 B() 是一个很好的优化候选者,并将其编译为本机代码,从而使其速度更快.又过了一段时间,JVM 可能决定内联对 B() 的调用,将其代码合并到 A() 中.

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.

最坏的情况是,该成本可能会分配给同级调用,而不是调用者.例如,我目前正在使用 VisualVM 分析一个应用程序,其中一个热点似乎ArrayList.size() 方法.在我的 Java 实现中,该方法是一个简单的字段 getter,任何 JVM 都应该快速内联.然而,分析器将其显示为一个主要的时间消耗者,完全忽略了一堆附近的 HashMap 调用,这些调用显然要贵得多.

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 选项卡提供的分析器,本质上记录所选代码中的每个方法入口和出口.不幸的是,检测分析器对被分析的代码有相当大的影响:

The only way to avoid these weaknesses is to use an instrumenting profiler, rather than a sampling one. Instrumenting profilers, such as the one provided by the Profiler tab in VisualVM essentially record each and every method entry and exit in the selected code. Unfortunately, instrumenting profilers have a rather heavy impact on the profiled code:

  • 他们在每个方法周围插入他们的监控代码,这完全改变了 JVM 处理方法的方式.由于额外的代码,即使是简单的字段 getter/setter 方法也可能不再内联,从而扭曲任何结果.探查器通常会尝试考虑这些更改,但并不总是成功.

  • They insert their monitoring code around each method, which completely changes the way a method is treated by the JVM. Even simple field getter/setter methods may not be inlined any more due to the extra code, thus skewing any results. The profiler usually tries to account for these changes, but it is not always successful.

它们会导致被分析的代码大量变慢,这使得它们完全不适合监控完整的应用程序.

They cause massive slow-downs to the profiled code, which makes them completely unsuitable for monitoring complete applications.

出于这些原因,检测分析器最适合分析已使用其他方法(例如采样分析器)检测到的热点.通过仅检测一组选定的类和/或方法,可以将分析副作用限制在应用程序的特定部分.

For these reasons instrumenting profilers are mostly suitable for analyzing hotspots that have already been detected using another method such as a sampling profiler. By instrumenting only a selected set of classes and/or methods it is possible to restrict the profiling side-effects to specific parts of an application.

这篇关于为什么 VisualVM Sampler 不提供有关 CPU 负载(方法时间执行)的完整信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆