国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
通過JMX控制在full GC前后做heap dump

有時候我們想知道一個Java程序在一次full GC的時候到底回收了哪些對象。特別是當(dāng)full GC看起來很頻密但系統(tǒng)看起來卻又沒有內(nèi)存泄漏的時候,了解究竟是哪些對象引致了這些GC會對調(diào)優(yōu)有幫助。

做了個簡單的例子,講解一種簡單的辦法在full GC的前后得到heap dump。本文說的辦法只能在HotSpot VM上使用;其它JVM要達(dá)到同樣的目的或許有其它做法,回頭有機(jī)會再說。
(同樣的工作在JRockit或者J9上做似乎都更容易些…


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

一般獲取heap dump的辦法

1、jmap
大家最熟悉的辦法或許就是JDK自帶的命令行工具jmap了。jmap可以在任何時候連接到一個跑在HotSpot VM的Java進(jìn)程上,根據(jù)需要制作HPROF格式的heap dump。
Command prompt代碼  
  1. jmap -dump:format=b,file=<filename> <pid>  

這是最常用的用法。

在Sun的JDK 5和JDK 1.4.2的后期版本中(JDK 5 update 17和JDK 1.4.2 update 16或更高版本),還可以在啟動參數(shù)里加上-XX:+HeapDumpOnCtrlBreak,然后通過ctrl + break或者發(fā)生SIGQUIT來讓VM生成heap dump。
不過這個參數(shù)在Sun JDK 6里不存在;JDK6上直接用jmap更方便些,倒也沒關(guān)系。
JRockit R28倒是支持使用這個參數(shù)。

2、JConsole、VisualVM、MAT
這幾個工具都封裝了heap dump的功能,用起來很方便——只要知道如何讓這些工具連接到目標(biāo)進(jìn)程上。所以它們通常在本地使用很方便,而要連接遠(yuǎn)程進(jìn)程就麻煩一些。
還有別的一些工具也有提供生成heap dump功能的,不過我一下想不起來了就只寫了上面仨。
GCMV或許也可以吧…呃,剛看了下,不行。還是得在VM里配置參數(shù)來生成heap dump。

JConsole:


VisualVM:



Eclipse Memory Analyzer (MAT):


3、JMX的API
Sun JDK通過JMX暴露出HotSpotDiagnosticMXBean,可以用于獲取VM信息。它支持dumpHeap(String outputFile, boolean live)操作,讓Java程序能直接指定路徑和是否只要活對象進(jìn)行heap dump。使用方法可以參考下面的鏈接:A. Sundararajan's Weblog: Programmatically dumping heap from Java applications

通過Serviceability Agent API也可以做heap dump。事實(shí)上jmap的其中一個模式就是包裝了SA API的sun.jvm.hotspot.tools.HeapDumper來完成功能的。

4、JVMTI
很老的版本的JVMTI API里曾經(jīng)有過heap dump函數(shù),不過后來被去掉了

5、讓JVM在一些特定事件發(fā)生的時候自動做heap dump
(這就是HotSpot操作起來沒有JRockit和J9方便的地方了…)
有時候我們只想在發(fā)生OutOfMemoryError的時候讓JVM自動生成一個heap dump出來,以便做事后分析。這種時候設(shè)置啟動參數(shù)-XX:+HeapDumpOnOutOfMemoryError即可。參考下面的文章來了解該參數(shù)的一些歷史:
Alan Bateman: Heap dumps are back with a vengeance!

HotSpot VM支持其它事件觸發(fā)heap dump么?參考官方文檔
引用
Flags marked as manageable are dynamically writeable through the JDK management interface (com.sun.management.HotSpotDiagnosticMXBean API) and also through JConsole. In Monitoring and Managing Java SE 6 Platform Applications, Figure 3 shows an example. The manageable flags can also be set through jinfo -flag.

聲明為manageable的參數(shù)可以在運(yùn)行時通過JMX修改。與heap dump相關(guān)的有以下4個參數(shù):
hotspot/src/share/vm/runtime/globals.hpp
C++代碼  
  1. manageable(bool, HeapDumpBeforeFullGC, false,                             \  
  2.         "Dump heap to file before any major stop-world GC")               \  
  3.                                                                           \  
  4. manageable(bool, HeapDumpAfterFullGC, false,                              \  
  5.         "Dump heap to file after any major stop-world GC")                \  
  6.                                                                           \  
  7. manageable(bool, HeapDumpOnOutOfMemoryError, false,                       \  
  8.         "Dump heap to file when java.lang.OutOfMemoryError is thrown")    \  
  9.                                                                           \  
  10. manageable(ccstr, HeapDumpPath, NULL,                                     \  
  11.         "When HeapDumpOnOutOfMemoryError is on, the path (filename or"    \  
  12.         "directory) of the dump file (defaults to java_pid<pid>.hprof"    \  
  13.         "in the working directory)")                                      \  

可以看到,除了HeapDumpOnOutOfMemoryError之外,還有HeapDumpBeforeFullGCHeapDumpAfterFullGC參數(shù),分別用于指定在full GC之前與之后生成heap dump。

順帶一提,前面VisualVM的截圖里“Disable Heap Dump on OOME”的功能,就是通過HotSpotDiagnosticMXBean將HeapDumpOnOutOfMemoryError參數(shù)設(shè)置為false來實(shí)現(xiàn)的。

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

通過JMX API在full GC前后生成heap dump的例子

原始代碼放在這里了:https://gist.github.com/978336

很簡單,就是演示了:
·獲取HotSpotDiagnosticMXBean;
·通過它上面的setVMOption(String name, String value)方法修改HeapDumpBeforeFullGCHeapDumpAfterFullGC參數(shù)為true;
·觸發(fā)一次full GC;
·將VM參數(shù)恢復(fù)為false。

為了方便,例子用Groovy來寫。要在Groovy Shell中看到GC的日志,可以設(shè)置環(huán)境變量JAVA_OPTIONS=-XX:+PrintGCDetails,或者是在當(dāng)前目錄放一個.hotspotrc來配置這個參數(shù);我是用的后者。

具體代碼:
Groovysh代碼  
  1. $ groovysh  
  2. [GC [PSYoungGen: 14016K->1312K(16320K)] 14016K->1312K(53696K), 0.0111510 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]   
  3. [GC [PSYoungGen: 15328K->2272K(30336K)] 15328K->4832K(67712K), 0.0286280 secs] [Times: user=0.02 sys=0.03, real=0.03 secs]   
  4. Groovy Shell (1.7.7, JVM: 1.6.0_25)  
  5. Type 'help' or '\h' for help.  
  6. ----------------------------------------------------------------------------------------------------------------------------  
  7. groovy:000> import java.lang.management.ManagementFactory  
  8. ===> [import java.lang.management.ManagementFactory]  
  9. groovy:000> import com.sun.management.HotSpotDiagnosticMXBean  
  10. ===> [import java.lang.management.ManagementFactory, import com.sun.management.HotSpotDiagnosticMXBean]  
  11. groovy:000>   
  12. groovy:000> HOTSPOT_BEAN_NAME = "com.sun.management:type=HotSpotDiagnostic"  
  13. ===> com.sun.management:type=HotSpotDiagnostic  
  14. groovy:000> server = ManagementFactory.platformMBeanServer  
  15. [GC [PSYoungGen: 30304K->2288K(30336K)] 32864K->8856K(67712K), 0.0643130 secs] [Times: user=0.16 sys=0.01, real=0.07 secs]   
  16. ===> com.sun.jmx.mbeanserver.JmxMBeanServer@7297e3a5  
  17. groovy:000> bean = ManagementFactory.newPlatformMXBeanProxy(server, HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean)  
  18. ===> MXBeanProxy(com.sun.jmx.mbeanserver.JmxMBeanServer@7297e3a5[com.sun.management:type=HotSpotDiagnostic])  
  19. groovy:000> bean.setVMOption('HeapDumpBeforeFullGC''true')  
  20. ===> null  
  21. groovy:000> bean.setVMOption('HeapDumpAfterFullGC''true')  
  22. ===> null  
  23. groovy:000> System.gc()  
  24. [GC [PSYoungGen: 10460K->2288K(58368K)] 17028K->9639K(95744K), 0.0166920 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]   
  25. [Heap Dump: Dumping heap to java_pid16836.hprof ...  
  26. Heap dump file created [20066598 bytes in 0.347 secs]  
  27. 0.3514030 secs][Full GC (System) [PSYoungGen: 2288K->0K(58368K)] [PSOldGen: 7351K->9621K(37376K)] 9639K->9621K(95744K) [PSPermGen: 18626K->18626K(37824K)], 0.1324840 secs] [Times: user=0.12 sys=0.02, real=0.14 secs]   
  28. [Heap DumpDumping heap to java_pid16836.hprof.1 ...  
  29. Heap dump file created [20013677 bytes in 0.340 secs]  
  30. 0.3398950 secs]===> null  
  31. groovy:000> bean.setVMOption('HeapDumpBeforeFullGC''false')  
  32. ===> null  
  33. groovy:000> bean.setVMOption('HeapDumpAfterFullGC''false')  
  34. ===> null  
  35. groovy:000> quit  
  36. Heap  
  37.  PSYoungGen      total 58368K, used 9250K [0x00000000edc000000x00000000f17400000x0000000100000000)  
  38.   eden space 56064K, 16% used [0x00000000edc00000,0x00000000ee5089b0,0x00000000f12c0000)  
  39.   from space 2304K, 0% used [0x00000000f1500000,0x00000000f1500000,0x00000000f1740000)  
  40.   to   space 2304K, 0% used [0x00000000f12c0000,0x00000000f12c0000,0x00000000f1500000)  
  41.  PSOldGen        total 37376K, used 9621K [0x00000000c94000000x00000000cb8800000x00000000edc00000)  
  42.   object space 37376K, 25% used [0x00000000c9400000,0x00000000c9d65410,0x00000000cb880000)  
  43.  PSPermGen       total 37824K, used 18758K [0x00000000c42000000x00000000c66f00000x00000000c9400000)  
  44.   object space 37824K, 49% used [0x00000000c4200000,0x00000000c5451ba8,0x00000000c66f0000)  

這樣就得到了 java_pid16836.hprof 與 java_pid16836.hprof.1 兩個heap dump文件。

把第二個heap dump文件改名為 java_pid16836.1.hprof 之后,用MAT打開這兩個heap dump,在第一個文件的histogram試圖下可以看到


目前MAT只支持histogram試圖中比較兩個heap dump。
點(diǎn)擊上方工具條最右邊的“<->”按鈕,并選上第二個heap dump文件之后,可以看到:


這樣就能很方便的得知這次full GC當(dāng)中到底收集了多少個什么類型的對象。
實(shí)際效果跟手動用jmap -histo比較差不多,不過要精確的在full GC前后手動做些操作不是件簡單的事情。

或許會有人想說,為啥MAT不能直接把具體是哪些對象被收集了顯示出來呢?
這功能不好做。GC的時候?qū)ο罂赡軙灰苿?,也就是說不能通過地址來將full GC前后的兩個heap dump里的記錄關(guān)聯(lián)到一起;而HPROF格式也沒有記錄足夠信息讓多個heap dump之間能建立起聯(lián)系。
結(jié)果能很方便做比較的就只有按類型做的統(tǒng)計(jì)。通常這也能提供有用的頭緒去進(jìn)一步做分析了。

P.S. 如果一個HPROF的heap dump是在開了壓縮指針的64位JVM上生成的,那么用MAT查看的時候,里面顯示的Shallow Heap和Retained Heap數(shù)據(jù)都會是錯誤的。因?yàn)镠PROF格式只能分辨是32位還是64位的,卻沒有記錄有沒有開壓縮指針、每個對象實(shí)際的大小是多少。這種條件下請不要相信MAT(或其它分析HPROF格式的heap dump的工具)顯示的對象大小。

(###)
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JVM性能調(diào)優(yōu)監(jiān)控工具jps、jstack、jmap、jhat、jstat、hprof使用詳解
JVisualVM簡介與內(nèi)存泄漏實(shí)戰(zhàn)分析
Java 堆內(nèi)存溢出梗概分析
JVM GC日志和內(nèi)存DUMP參數(shù)配置
JVM調(diào)優(yōu)
JVM性能調(diào)優(yōu)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服