转载自 http://rednaxelafx.iteye.com/blog/1021619
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的情况
Groovysh代码
- D:sdkgroovy-1.7.2bin>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相关的方法。
Groovysh代码
- D:sdkgroovy-1.7.2bin>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