JDK6u25里添加的按线程统计分配内存量: JMX

Oracle几天前发布的JDK 6 update 25里添加的一个新功能非常有趣,可以按照线程来跟踪(GC堆)内存的分配量。这个功能在VM核心、解释器、C1编译器、C2编译器以及GC中都有代码支持,并且通过JMX API暴露出来。
不过新加的这功能不是加在java.开头的包里,而是加在com.sun.management.ThreadMXBean这个接口上,要用的话还得cast一下。

当然,这么底层的功能不可能没有代价。添加这个功能后,在GC堆上分配空间的slow-path会比以前稍微慢一些。但希望对整体性能的影响并不大吧。
Fast-path是在TLAB上分配空间的,而TLAB的分配数据是在TLAB refill的时候才批量更新,所以这个功能对fast-path的执行效率基本上没影响,以稍微放宽数据精准性为代价。

相关链接:
Bug ID 7003271: Hotspot should track cumulative Java heap bytes allocated on a per-thread basis
changeset

JMX中,该功能由ThreadMXBean上新增的几个方法提供。详情可见下面例子。
ThreadMXBean.getThreadAllocatedBytes(long threadId)的用法基本上可以看成跟System.currentTimeMillis()用于计时的用法一样,在两点上记录并且求差即可。

不知道为什么JVMTI没得到这个更新,或许是因为更新JVMTI spec涉及committee stuff?

==============================================================

直接拿一段Groovy脚本来演示吧:

先看JDK 6 update 24的情况
D:\sdk\groovy-1.7.2\bin>groovysh
Groovy Shell (1.7.2, JVM: 1.6.0_24)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------
groovy:000> import java.lang.management.*
===> [import java.lang.management.*]
groovy:000> tb = ManagementFactory.threadMXBean
===> sun.management.ThreadImpl@8b677f
groovy:000> tb.class.methods.name.unique().sort()
===> [dumpAllThreads, equals, findDeadlockedThreads, findMonitorDeadlockedThreads, getAllThreadIds, getClass, getCurrentThreadCpuTime, getCurrentThreadUserTime, getDaemonThreadCount, getPeakThreadCount, getThreadCount, getThreadCpuTime, getThreadInfo, getThreadUserTime, getTotalStartedThreadCount, hashCode, isCurrentThreadCpuTimeSupported, isObjectMonitorUsageSupported, isSynchronizerUsageSupported, isThreadContentionMonitoringEnabled, isThreadContentionMonitoringSupported, isThreadCpuTimeEnabled, isThreadCpuTimeSupported, notify, notifyAll, resetPeakThreadCount, setThreadContentionMonitoringEnabled, setThreadCpuTimeEnabled, toString, wait]
groovy:000> tb.class.methods.findAll { it.name =~ /Alloc/}.each { println it }; null
===> null

这个时候ThreadMXBean上还没有跟alloc相关的方法。

D:\sdk\groovy-1.7.2\bin>groovysh
Groovy Shell (1.7.2, JVM: 1.6.0_25)
Type 'help' or '\h' for help.
-------------------------------------------------------------------------------
groovy:000> import java.lang.management.*
===> [import java.lang.management.*]
groovy:000> tb = ManagementFactory.threadMXBean
===> sun.management.ThreadImpl@9b1670
groovy:000> tb.class.methods.name.unique().sort()
===> [dumpAllThreads, equals, findDeadlockedThreads, findMonitorDeadlockedThreads, getAllThreadIds, getClass, getCurrentThreadCpuTime, getCurrentThreadUserTime, getDaemonThreadCount, getPeakThreadCount, getThreadAllocatedBytes, getThreadCount, getThreadCpuTime, getThreadInfo, getThreadUserTime, getTotalStartedThreadCount, hashCode, isCurrentThreadCpuTimeSupported, isObjectMonitorUsageSupported, isSynchronizerUsageSupported, isThreadAllocatedMemoryEnabled, isThreadAllocatedMemorySupported, isThreadContentionMonitoringEnabled, isThreadContentionMonitoringSupported, isThreadCpuTimeEnabled, isThreadCpuTimeSupported, notify, notifyAll, resetPeakThreadCount, setThreadAllocatedMemoryEnabled, setThreadContentionMonitoringEnabled, setThreadCpuTimeEnabled, toString, wait]
groovy:000> tb.class.methods.findAll { it.name =~ /Alloc/}.each { println it };
null
public boolean sun.management.ThreadImpl.isThreadAllocatedMemoryEnabled()
public boolean sun.management.ThreadImpl.isThreadAllocatedMemorySupported()
public long[] sun.management.ThreadImpl.getThreadAllocatedBytes(long[])
public long sun.management.ThreadImpl.getThreadAllocatedBytes(long)
public void sun.management.ThreadImpl.setThreadAllocatedMemoryEnabled(boolean)
===> null
groovy:000> tb.threadAllocatedMemoryEnabled
===> true
groovy:000> tid = Thread.currentThread().id
===> 1
groovy:000> tb.getThreadAllocatedBytes(tid)
===> 48106672
groovy:000> tb.getThreadAllocatedBytes(tid)
===> 48751520
groovy:000> tb.getThreadAllocatedBytes(tid)
===> 49384752
groovy:000> tb.getThreadAllocatedBytes(tid)
===> 50086240
groovy:000> quit

你可能感兴趣的:(jvm,jdk,oracle,sun,groovy)