轉自:http://blog.csdn.net/gzh0222/article/details/8538727java
一、爲何會發生內存泄漏服務器
Java 如何檢測內在泄漏呢?咱們須要一些工具進行檢測,並發現內存泄漏問題,否則很容易發生down機問題。併發
編寫java程序最爲方便的地方就是咱們不須要管理內存的分配和釋放,一切由jvm來進行處理,當java對象再也不被應用時,等到堆內存不夠用時,jvm會進行垃圾回收,清除這些對象佔用的堆內存空間,若是對象一直被應用,jvm沒法對其進行回收,建立新的對象時,沒法從Heap中獲取足夠的內存分配給對象,這時候就會致使內存溢出。而出現內存泄露的地方,通常是不斷的往容器中存放對象,而容器沒有相應的大小限制或清除機制。容易致使內存溢出。
當服務器應用佔用了過多內存的時候,如何快速定位問題呢?如今,Eclipse MAT的出現使這個問題變得很是簡單。EclipseMAT是著名的SAP公司貢獻的一個工具,能夠在Eclipse網站下載到它,徹底免費的。
要定位問題,首先你須要獲取服務器jvm某刻內存快照。jdk自帶的jmap能夠獲取內存某一時刻的快照,導出爲dmp文件後,就能夠用Eclipse MAT來分析了,找出是那個對象使用內存過多。jvm
二、內存泄漏的現象:工具
經常地,程序內存泄漏的最初跡象發生在出錯以後,在你的程序中獲得一個OutOfMemoryError。這種典型的狀況發生在產品環境中,而在那裏,你但願內存泄漏盡量的少,調試的可能性也達到最小。也許你的測試環境和產品的系統環境不盡相同,致使泄露的只會在產品中暴露。這種狀況下,你須要一個低負荷的工具來監聽和尋找內存泄漏。同時,你還須要把這個工具同你的系統聯繫起來,而不須要從新啓動他或者機械化你的代碼。也許更重要的是,當你作分析的時候,你須要可以同工具分離而使得系統不會受到干擾。
一個OutOfMemoryError經常是內存泄漏的一個標誌,有可能應用程序的確用了太多的內存;這個時候,你既不能增長JVM的堆的數量,也不能改變你的程序而使得他減小內存使用。可是,在大多數狀況下,一個OutOfMemoryError是內存泄漏的標誌。一個解決辦法就是繼續監聽GC的活動,看看隨時間的流逝,內存使用量是否會增長,若是有,程序中必定存在內存泄漏。性能
三、發現內存泄漏學習
1. jstat -gc pid測試
能夠顯示gc的信息,查看gc的次數,及時間。網站
其中最後五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。spa
2.jstat -gccapacity pid
能夠顯示,VM內存中三代(young,old,perm)對象的使用和佔用大小,
如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,
PGC是當前新生成的perm內存佔用量,PC是但前perm內存佔用量。
其餘的能夠根據這個類推, OC是old內純的佔用量。
3.jstat -gcutil pid
統計gc信息統計。
4.jstat -gcnew pid
年輕代對象的信息。
5.jstat -gcnewcapacity pid
年輕代對象的信息及其佔用量。
6.jstat -gcold pid
old代對象的信息。
7.stat -gcoldcapacity pid
old代對象的信息及其佔用量。
8.jstat -gcpermcapacity pid
perm對象的信息及其佔用量。
9.jstat -class pid
顯示加載class的數量,及所佔空間等信息。
10.jstat -compiler pid
顯示VM實時編譯的數量等信息。
11.stat -printcompilation pid
當前VM執行的信息。
一些術語的中文解釋:
S0C:年輕代中第一個survivor(倖存區)的容量 (字節)
S1C:年輕代中第二個survivor(倖存區)的容量 (字節)
S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (字節)
S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (字節)
EC:年輕代中Eden(伊甸園)的容量 (字節)
EU:年輕代中Eden(伊甸園)目前已使用空間 (字節)
OC:Old代的容量 (字節)
OU:Old代目前已使用空間 (字節)
PC:Perm(持久代)的容量 (字節)
PU:Perm(持久代)目前已使用空間 (字節)
YGC:從應用程序啓動到採樣時年輕代中gc次數
YGCT:從應用程序啓動到採樣時年輕代中gc所用時間(s)
FGC:從應用程序啓動到採樣時old代(全gc)gc次數
FGCT:從應用程序啓動到採樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啓動到採樣時gc用的總時間(s)
NGCMN:年輕代(young)中初始化(最小)的大小 (字節)
NGCMX:年輕代(young)的最大容量 (字節)
NGC:年輕代(young)中當前的容量 (字節)
OGCMN:old代中初始化(最小)的大小 (字節)
OGCMX:old代的最大容量 (字節)
OGC:old代當前新生成的容量 (字節)
PGCMN:perm代中初始化(最小)的大小 (字節)
PGCMX:perm代的最大容量 (字節)
PGC:perm代當前新生成的容量 (字節)
S0:年輕代中第一個survivor(倖存區)已使用的佔當前容量百分比
S1:年輕代中第二個survivor(倖存區)已使用的佔當前容量百分比
E:年輕代中Eden(伊甸園)已使用的佔當前容量百分比
O:old代已使用的佔當前容量百分比
P:perm代已使用的佔當前容量百分比
S0CMX:年輕代中第一個survivor(倖存區)的最大容量 (字節)
S1CMX :年輕代中第二個survivor(倖存區)的最大容量 (字節)
ECMX:年輕代中Eden(伊甸園)的最大容量 (字節)
DSS:當前須要survivor(倖存區)的容量 (字節)(Eden區已滿)
TT:持有次數限制
MTT :最大持有次數限制
若是定位內存泄漏問題我通常使用以下命令:
Jstat -gcutil15469 2500 70
[root@ssss logs]# jstat -gcutil 15469 1000 300
S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 1.46 26.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 46.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 47.04 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 65.19 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 67.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 87.54 4.61 30.14 35 0.872 0 0.000 0.872
0.00 1.46 88.03 4.61 30.14 35 0.872 0 0.000 0.872
1.48 0.00 5.56 4.62 30.14 36 0.874 0 0.000 0.874
1000 表明多久間隔顯示一次,
100 表明顯示一次。
S0 — Heap上的 Survivor space 0 區已使用空間的百分比
S1 — Heap上的 Survivor space 1 區已使用空間的百分比
E — Heap上的 Eden space 區已使用空間的百分比
O — Heap上的 Old space 區已使用空間的百分比
P — Perm space 區已使用空間的百分比
YGC — 從應用程序啓動到採樣時發生 Young GC 的次數
YGCT– 從應用程序啓動到採樣時 Young GC 所用的時間(單位秒)
FGC — 從應用程序啓動到採樣時發生 Full GC 的次數
FGCT– 從應用程序啓動到採樣時 Full GC 所用的時間(單位秒)
GCT — 從應用程序啓動到採樣時用於垃圾回收的總時間(單位秒)
若是有大量的FGC就要查詢是否有內存泄漏的問題了,圖中的FGC數量就比較大,而且執行時間較長,這樣就會致使系統的響應時間較長,若是對jvm的內存設置較大,那麼執行一次FGC的時間可能會更長。
若是爲了更好的證實FGC對服務器性能的影響,咱們可使用java visualVM來查看一下:
從上圖能夠發現執行FGC的狀況,下午3:10分以前是沒有FGC的,以後出現大量的FGC。
上圖是jvm堆內存的使用狀況,下午3:10分以前的內存回收仍是比較合理,可是以後大量內存沒法回收,最後致使內存愈來愈少,致使大量的full gc。
下面咱們在看看大量full GC對服務器性能的影響,下面是我用loadrunner對咱們項目進行壓力測試相應時間的截圖:
從圖中能夠發現有,在進行full GC後系統的相應時間有了明顯的增長,點擊率和吞吐量也有了明顯的降低。因此java內存泄漏對系統性能的影響是不可忽視的。
三、定位內存泄漏
固然經過上面幾種方法咱們能夠發現java的內存泄漏問題,可是做爲一名合格的高級工程師,確定不甘心就把這樣的結論交給開發,固然這也的結論交給開發,開發也很難定位問題,爲了更好的提供本身在公司的地位,咱們必須給開發工程師提供更深刻的測試結論,下面就來認識一下MemoryAnalyzer.exe。java內存泄漏檢查工具利器。
首先咱們必須對jvm的堆內存進行dump,只有拿到這個文件咱們才能分析出jvm堆內存中到底存了些什麼內容,到底在作什麼?
MemoryAnalyzer的用戶我在這裏就不一一說明了,個人博客裏也有說明,下面就展現我測試的成功圖:
其中深藍色的部分就爲內存泄漏的部分,java的堆內存一共只有481.5M而內存泄漏的部分獨自佔有了336.2M因此本次的內存泄漏很明顯,那麼我就來看看那個方法致使的內存泄漏:
從上圖咱們能夠發現紅線圈着的方法佔用了堆內存的67.75%,若是能把這個測試結果交給開發,開發是否是應該很好定位呢。因此做爲一名高級測試工程師,咱們須要學習的東西太多。
雖然不肯定必定是內存泄漏,可是能夠準確的告訴開發問題出現的緣由,有必定的說服力。