一般線上遇到比較頭疼的就是OOM內存溢出問題,我們都會先看錯誤日志,如果錯誤日志能夠定位出哪個類對象導致內存溢出,那么我們只需要針對問題修改bug就好。但是很多時候我們單憑日志無法定位出內存溢出問題,那么我們這時候就需要以下操作來定位問題。
1、top下對當前服務器內存有個大致了解
top后 shift+M俺內存占用由大到小排序,RES是此進程實際占用內存,%MEM是占服務器總內存的49.8。
2、利用ps命令查看服務pid
[root@speedyao java]# ps -aux|grep java
3、利用jstat查看虛擬機gc情況
jstat -gc:util <vmid> [<interval> [<count>]
vmid:虛擬機進程號
interval:采樣時間,默認單位是ms
count:采樣條數
[root@speedyao java]# jstat -gcutil 17561 1000 10
以上命令代表1秒鍾采樣1次,總共采樣10次。
FULL GC明顯大於YOUNG GC次數,並且FULL GC次數很頻繁,說明程序有大內存對象,並且一直無法釋放。
4、生成dump文件,有兩種方式。 一種是利用jmap直接生成dump文件;另一種是利用gcore先生成core文件,再根據core文件利用jmap生成dump文件。
(1)先說第一種,這種比較簡單,使用這種方案的時候請注意:JVM會將整個heap的信息dump寫入到一個文件,heap如果比較大的話,就會導致這個過程比較耗時,並且執行的過程中為了保證dump的信息是可靠的,所以會暫停應用。
[root@speedyao java]# jmap -dump:format=b,file=heap.prof 17561
format=b:表示生成二進制類型的dump文件
file=:后面寫的是輸出的dump文件路徑
17561:jvm進程id
(2)接下來是第二種。這一種在jmap轉換core文件的時候比較耗時,並且生成的dump文件用mat打開的時候分析結果不太正確,不太好定位問題。所以我建議使用第一種,雖然會造成服務掛起吧,但是結果總歸是正確的。
利用gcore保存服務的內存信息,因為gcore比jmap的dump會快很多,也不對線上服務有大的影響
[root@speedyao java]# gdb -q --pid=17561
generate-core-file:生成內存對象,生成的文件存儲在當前位置,文件格式pid.core
detach:斷開與進程的連接
quit:退出
利用jmap將gcore文件轉換為java的dump文件,這一步執行的比較慢,可以用nohup執行,以防止誤點Ctrl+C導致退出。
[root@speedyao java]# jmap -dump:format=b,file=heap.prof /usr/bin/java core.17561
format=b:表示生成二進制類型的dump文件
file=:后面寫的是輸出的dump文件路徑
/usr/bin/java:java命令路徑,可以通過命令which java 獲取這個路徑
core.17561:表示core文件路徑
6、利用MAT(eclipse開發的可以下載eclipse插件,idea開發的可以下載單獨的MAT壓縮包)分析dump文件。當然也可以用jdk自帶的jvisualvm.exe來分析dump文件
上圖是概要,陰影部分就是大內存對象類,點擊選擇 “list Object”、“with incoming references”,就出現下圖。下圖就是這個對象的信息,RunMian 就是map對象所在的類,這樣就能快速定位出哪個類中的哪個對象出現了內存異常。
下圖Histogram這個tab是堆內存占比從大到小排序。
以上就是內存問題排查的大致步驟。
轉載於:https://blog.csdn.net/u010430495/article/details/87283064?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.control