JDK6u25裡新增的按執行緒統計分配記憶體量: JMX
轉載自 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的執行效率基本上沒影響,以稍微放寬資料精準性為代價。
相關連結:
changeset
JMX中,該功能由ThreadMXBean上新增的幾個方法提供。詳情可見下面例子。
ThreadMXBean.getThreadAllocatedBytes(long threadId)的用法基本上可以看成跟System.currentTimeMillis()用於計時的用法一樣,在兩點上記錄並且求差即可。
不知道為什麼JVMTI沒得到這個更新,或許是因為更新JVMTI spec涉及committee stuff?
==============================================================
直接拿一段Groovy指令碼來演示吧:
先看JDK 6 update 24的情況
Groovysh程式碼
- 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
- ===> [email protected]
- 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:\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
- ===> [email protected]
- 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