【发布时间】:2011-07-20 03:36:02
【问题描述】:
我编写了这个小(而且效率极低)的类,并希望使用 Java VisualVM 对其进行分析。
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
br.readLine();
int n = Integer.parseInt(args[0]);
int fib = fib(n);
System.out.println(fib);
}
private static int fib(int n) {
if (n < 2) {
return n;
}
return fib(n-1)+fib(n-2);
}
}
结果很奇怪。结果完全由对 ConnectionHandler.run() 的调用支配。
(98.2%) sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run()
(1.7%) java.lang.Thread.join(long)
(0%) java.lang.String.equals(Object)
等等……
大概有大约一百种方法被分析,其中没有一个是 fib(int)!
令人难以置信的是,我的程序实际上将所有时间都花在了这些方法上。他们似乎是连接到我的 jvm 并做它的事情的分析器。
我做错了什么?
为清楚起见进行了编辑:如果您为 n 传递 45,则此应用程序将运行 20 秒。我最初分析的程序(不是斐波那契计算器)将我的 cpu 上的所有四个内核都固定在 100% 上,并且我正在执行长达 5 分钟的分析运行。这些具有相同的结果,并且我的应用程序中的方法没有出现在热点方法列表中。
它因运行而异,但 ConnectionHandler.run() 始终位于顶部,通常占分析时间的约 99%。
第二次编辑:我已经尝试使用采样器,现在得到的结果与 JProfiler 产生的结果一致。这样做的缺点是我没有得到分析附带的堆栈跟踪信息。但对于我的迫切需要,这非常好。
我在玩游戏时发现的一点是,VisualVM 在分析方法调用时会计算挂钟时间。
在我的具体情况下,我的应用程序有一个主线程,它启动工作线程并立即阻塞等待队列中的消息。
这意味着阻塞方法似乎会占用探查器上的几乎所有时间,尽管事实上并不是这种方法占用了我的 CPU。
我希望 sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run() 方法也是如此,它可以很好地完成工作 - 但是当它终止时,它会成为我的应用程序中运行时间最长的方法之一- 反复。
【问题讨论】:
-
您使用的是 CPU 采样器还是插桩分析器?使用了哪些设置?您似乎正在使用 CPU 采样器(由于采样粒度等原因可能会得到有偏差的结果),或者您的分析设置未正确设置。
-
这就是你可以用一些分析器得到的那种疯狂的东西。当您试图弄清楚这一点时,只需尝试this method。
-
看起来您遇到了与 Glunk 相同的问题:stackoverflow.com/questions/3243100/… 这似乎是 jvisualvm 方法检测缺陷,如果您从 main 调用它就无法重新定义。
-
@JB 感谢您指出采样模式。
-
@FrancisStephens 你能告诉我哪些设置适合你吗?