1、jdk工具之jps(JVM Process Status Tools)命令使用html
2、jdk命令之javah命令(C Header and Stub File Generator)java
3、jdk工具之jstack(Java Stack Trace)算法
4、jdk工具之jstat命令(Java Virtual Machine Statistics Monitoring Tool)緩存
4、jdk工具之jstat命令2(Java Virtual Machine Statistics Monitoring Tool)詳解app
5、jdk工具之jmap(java memory map)、 mat之四--結合mat對內存泄露的分析eclipse
6、jdk工具之jinfo命令(Java Configuration Info)jvm
7、jdk工具之jconsole命令(Java Monitoring and Management Console)工具
8、jdk工具之JvisualVM、JvisualVM之二--Java程序性能分析工具Java VisualVMpost
9、jdk工具之jhat命令(Java Heap Analyse Tool)性能
10、jdk工具之Jdb命令(The Java Debugger)
11、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)
11、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)
12、jdk工具之jcmd介紹(堆轉儲、堆分析、獲取系統信息、查看堆外內存)
十3、jdk命令之Java內存之本地內存分析神器:NMT 和 pmap
打印出某個java進程(使用pid)內存內的,全部‘對象’的狀況(如:產生那些對象,及其數量)。
能夠輸出全部內存中對象的工具,甚至能夠將VM 中的heap,以二進制輸出成文本。使用方法 jmap -histo pid。若是連用SHELL jmap -histo pid>a.log能夠將其保存到文本中去,在一段時間後,使用文本對比工具,能夠對比出GC回收了哪些對象。jmap -dump:format=b,file=outfile 3024能夠將3024進程的內存heap輸出出來到outfile文件裏,再配合MAT(內存分析工具(Memory Analysis Tool),使用參見:http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)或與jhat (Java Heap Analysis Tool)一塊兒使用,可以以圖像的形式直觀的展現當前內存是否有問題。
查看該進程(pid)下堆內存的使用狀況:
jmap -heap pid
快速定位內存泄漏的方法:只統計存活的對象
jmap -histo:live pid
還能夠導出:
jmap -histo:live pid >1.txt將信息輸出到指定文件中
SYNOPSIS
jmap [ option ] pid
jmap [ option ] executable core
jmap [ option ] [server-id@]remote-hostname-or-IP
1)、options:
executable Java executable from which the core dump was produced.
(多是產生core dump的java可執行程序)
core 將被打印信息的core dump文件
remote-hostname-or-IP 遠程debug服務的主機名或ip
server-id 惟一id,假如一臺主機上多個遠程debug服務
2)、基本參數:
-dump:[live,]format=b,file=<filename> 使用hprof二進制形式,輸出jvm的heap內容到文件=. live子選項是可選的,假如指定live選項,那麼只輸出活的對象到文件.
-finalizerinfo 打印正等候回收的對象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用狀況.
-histo[:live] 打印每一個class的實例數目,內存佔用,類全名信息. VM的內部類名字開頭會加上前綴」*」. 若是live子參數加上後,只統計活的對象數量.
-permstat 打印classload和jvm heap長久層的信息. 包含每一個classloader的名字,活潑性,地址,父classloader和加載的class數量. 另外,內部String的數量和佔用內存數也會打印出來.
-F 強迫.在pid沒有相應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效.
-h | -help 打印輔助信息
-J 傳遞參數給jmap啓動的jvm.
pid 須要被打印配相信息的java進程id,創業與打工的區別 - 博文預覽,能夠用jps查問.
tasklist命令查看進程id(Tasklist"是 winxp/win2003/vista/win7/win8下的命令,用來顯示運行在本地或遠程計算機上的全部進程,帶有多個執行參數。)
經常使用的參數以下:
histo
jmap -histo pid 展現class的內存狀況
展現的信息爲編號,實例數,字節,類名
-finalizerinfo
打印等待回收的對象信息
jmap -finalizerinfo 4783 Attaching to process ID 4783, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.171-b11 Number of objects pending for finalization: 0 [root@ip-172-29-206-104 applogs]#
heap
jmap -heap pid 展現pid的總體堆信息
jmap -heap 2464 JVM version is 16.3-b01 using thread-local object allocation. Parallel GC with 13 thread(s) Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 8436842496 (8046.0MB) NewSize = 5439488 (5.1875MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 88080384 (84.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 87883776 (83.8125MB) used = 31053080 (29.614524841308594MB) free = 56830696 (54.197975158691406MB) 35.33425782706469% used From Space: capacity = 13828096 (13.1875MB) used = 196608 (0.1875MB) free = 13631488 (13.0MB) 1.4218009478672986% used To Space: capacity = 16384000 (15.625MB) used = 0 (0.0MB) free = 16384000 (15.625MB) 0.0% used PS Old Generation capacity = 156172288 (148.9375MB) used = 27098208 (25.842864990234375MB) free = 129074080 (123.09463500976562MB) 17.35148299805917% used PS Perm Generation capacity = 88080384 (84.0MB) used = 50847592 (48.492042541503906MB) free = 37232792 (35.507957458496094MB) 57.728622073218936% used
說明以下
Parallel GC with 13 thread(s) #13個gc線程 Heap Configuration:#堆內存初始化配置 MinHeapFreeRatio = 40 #-XX:MinHeapFreeRatio設置JVM堆最小空閒比率 MaxHeapFreeRatio = 70 #-XX:MaxHeapFreeRatio設置JVM堆最大空閒比率 MaxHeapSize = 8436842496 (8046.0MB)#-XX:MaxHeapSize=設置JVM堆的最大大小 NewSize = 5439488 (5.1875MB) #-XX:NewSize=設置JVM堆的‘新生代’的默認大小 MaxNewSize = 17592186044415 MB #-XX:MaxNewSize=設置JVM堆的‘新生代’的最大大小 OldSize = 5439488 (5.1875MB) #-XX:OldSize=設置JVM堆的‘老生代’的大小 NewRatio = 2 #-XX:NewRatio=:‘新生代’和‘老生代’的大小比率 SurvivorRatio = 8 #-XX:SurvivorRatio=設置年輕代中Eden區與Survivor區的大小比值 PermSize = 21757952 (20.75MB) #-XX:PermSize=<value>:設置JVM堆的‘永生代’的初始大小 MaxPermSize = 88080384 (84.0MB) #-XX:MaxPermSize=<value>:設置JVM堆的‘永生代’的最大大小 Heap Usage: PS Young Generation Eden Space:#Eden區內存分佈 capacity = 87883776 (83.8125MB) used = 31053080 (29.614524841308594MB) free = 56830696 (54.197975158691406MB) 35.33425782706469% used From Space:#其中一個Survivor區的內存分佈 capacity = 13828096 (13.1875MB) used = 196608 (0.1875MB) free = 13631488 (13.0MB) 1.4218009478672986% used To Space:#另外一個Survivor區的內存分佈 capacity = 16384000 (15.625MB) used = 0 (0.0MB) free = 16384000 (15.625MB) 0.0% used PS Old Generation#當前的Old區內存分佈 capacity = 156172288 (148.9375MB) used = 27098208 (25.842864990234375MB) free = 129074080 (123.09463500976562MB) 17.35148299805917% used PS Perm Generation#當前的 「永生代」 內存分佈 capacity = 88080384 (84.0MB) used = 50847592 (48.492042541503906MB) free = 37232792 (35.507957458496094MB) 57.728622073218936% used
mat爲eclipse的一個內存分析插件,幫助查找內存泄漏和減小內存消耗。
首先基於jmap導出的堆信息
jmap -dump:live,format=b,file=test.bin 29030
準備代碼:
class User { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User(String id, String name) { super(); this.id = id; this.name = name; } }
main方法:
public static void main(String[] args) { List<User> list = new ArrayList<User>(); for (int i = 1; i < 10000; i++) { User o = new User(i + "", System.currentTimeMillis() + ""); list.add(o); o = null; } System.out.println("end"); try { Thread.sleep(100000000l); } catch (InterruptedException e) { e.printStackTrace(); } }
執行以後用jmap輸出堆信息
而後導入分析工具
咱們能夠看到圖形化展現:
而後咱們點擊
以下所示:
而後點擊詳情
咱們能夠看到有不少的User對象
這些對象有可能會溢出,而後咱們打開OQL窗口看他是否爲null,執行以下OQL語句
SELECT u FROM org.learn.util.User u WHERE (u.value = null)
也就是說這個是null,可是仍然有強引用存在,gc的時候是不能回收的,這樣就會出現內存的溢出問題
我用MAT打開了heap.bin,很容易看出,char[]的數量出其意料的多,佔用90%以上的內存 。通常來講,char[]在JVM確實會佔用不少內存,數量也很是多,由於String對象以char[]做爲內部存儲。可是此次的char[]太貪婪 了,仔細一觀察,發現有數萬計的char[],每一個都佔用數百K的內存 。這個現象說明,Java程序保存了數以萬計的大String對象 。結合程序的邏輯,這個是不該該的,確定在某個地方出了問題。
在可疑的char[]中,任意挑了一個,使用Path To GC Root功能,找到該char[]的引用路徑,發現String對象是被一個HashMap中引用的 。這個也是意料中的事情,Java的內存泄露多半是由於對象被遺留在全局的HashMap中得不到釋放。不過,該HashMap被用做一個緩存,設置了緩 存條目的閾值,導達到閾值後會自動淘汰。從這個邏輯分析,應該不會出現內存泄露的。雖然緩存中的String對象已經達到數萬計,但仍然沒有達到預先設置 的閾值(閾值設置地比較大,由於當時預估String對象都比較小)。
可是,另外一個問題引發了個人注意:爲何緩存的String對象如此巨大?內部char[]的長度達數百K。雖然緩存中的 String對象數量尚未達到閾值,可是String對象大小遠遠超出了咱們的預期,最終致使內存被大量消耗,造成內存泄露的跡象(準確說應該是內存消 耗過多) 。
就這個問題進一步順藤摸瓜,看看String大對象是如何被放到HashMap中的。經過查看程序的源代碼,我發現,確實有String大對象,不 過並無把String大對象放到HashMap中,而是把String大對象進行split(調用String.split方法),而後將split出 來的String小對象放到HashMap中 了。
這就奇怪了,放到HashMap中明明是split以後的String小對象,怎麼會佔用那麼大空間呢?難道是String類的split方法有問題?