使用JMX获取线程CPU时间的有效方法
我目前使用JMX以下列方式获得总线程CPU时间:
private long calculateTotalThreadCpuTime(ThreadMXBean thread) { long totalTime = 0l; for (ThreadInfo threadInfo : thread.dumpAllThreads(false, false)) totalTime += thread.getThreadCpuTime(threadInfo.getThreadId()); return totalTime; }
由于ThreadMXBean实际上是一个远程代理,性能是可怕的 ,在这个实际方法调用的秒数量级。
有更快的方法吗?
更新 :我正在使用它进行性能监控。 测量结果是“挂钟”时间和JProfiler,显示我花费大约85%的时间用于此方法。 我确实有一些其他MXBean调用(运行时,内存,GC),但它们便宜得多。 很可能因为每次调用thread.getThreadCpuTime
都是远程调用。
更新2 :显示性能问题的JProfiler屏幕截图。
如果您愿意使用非标准API,则可以将OperatingSystemMXBean
为com.sun.management.OperatingSystemMXBean
并调用getProcessCpuTime()
,如使用Sun内部类在David Robert Nadeau的博客上获取JVM CPU时间中所述 。
必须是您的呼叫的远程性质才是问题所在。
我最近在询问一个线程的CPU时间使用时出现了高峰,而且速度非常快。 在Web应用程序请求的上下文中,它几乎是无法估量的。 如果一个人进入硬循环,它会花费你,但通常你想在操作开始时和最后一次。
最佳化:
- 在线程池中调用getThreadCPUTime,因为它似乎是网络绑定的;
- 每当发现一个线程在
Thread.STATE.TERMINATED
,将其名称保存在Map中并在下次跳过查询。
性能不佳的原因是每次调用thread.getThreadCpuTime()
都会(在远程代理的情况下)最有可能导致RMI / Remote JMX调用,这当然是昂贵的,特别是当消息实际通过TCP(甚至可能在localhost之外)。 (参见JMX 1.4规范,第7.3章)
尽管JMX一次定义了多个属性检索 ,但这不会对您有所帮助,因为thread.getThreadCpuTime(long)
不是JMX属性而是远程方法调用(此外,调用方法的ThreadInfo对象因每次调用而thread.getThreadCpuTime(long)
)
不幸的是,JMX 1.4规范没有定义类似“调用多个对象的多个方法并返回它们的返回值”之类的东西 。 因此,除了这些调用的并发调用(这将节省时间但不会减少工作量)之外,我不知道这里有任何(兼容的)优化。
您能详细谈谈您计划如何使用这些信息吗? 您可以使用基于JVMTI的代理获取线程CPU时间,该代理的性能应该略好于JMX。 您是如何衡量JMX方法的开销导致您获得“可怕”性能的结论?