一、Java虛拟機邏輯回收機制
1、Java垃圾回收器
Java垃圾回收器是Java虛拟機(JVM)的三個重要子產品(另外兩個是解釋器和多線程機制)之一,為應用程式提供記憶體的自動配置設定(Memory Allocation)、自動回收(Garbage Collect)功能,這兩個操作都發生在Java堆上(一段記憶體快)。
某一個時點,一個對象如果有一個以上的引用(Rreference)指向它,那麼該對象就為活着的(Live),否則死亡(Dead),視為垃圾,可被垃圾回收器回收再利用。
回收操作需要消耗CPU、線程、時間等資源,是以容易了解的是垃圾回收操作不是實時的發生(對象死亡馬上釋放),當記憶體消耗完或者是達到某一個名額(Threshold,使用記憶體占總記憶體的比列,比如0.75)時,觸發垃圾回收操作。有一個對象死亡的例外,java.lang.Thread類型的對象即使沒有引用,隻要線程還在運作,就不會被回收。
依據統計分析可知,Java(包括一些其它進階語言)裡面大多數對象生命周期都是短暫的,是以把Java記憶體分代管理。分代的目的無非就是為不同代的記憶體塊運用不同的管理政策(算法),進而最大化性能。相對于年老代,通常年輕代要小很多,回收的頻率高,速度快。年老代則回收頻率低,耗時長。記憶體在年輕代裡面配置設定,年輕代裡面的對象經過多個回收周期依然存活的會自動晉升到年老代。
2、垃圾回收類型
所有的回收器類型都是基于分代技術。Java HotSpot虛拟機包含三代,年輕代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation)。
(1)永久代
存儲類、方法以及它們的描述資訊。可以通過-XX:PermSize=64m和-XX:MaxPermSize=128m兩個可選項指定初始大小和最大值。通常 我們不需要調節該參數,預設的永久代大小足夠了,不過如果加載的類非常多,不夠用了,調節最大值即可。
(2)年老代
主要存儲年輕代中經過多個回收周期仍然存活進而更新的對象,當然對于一些大的記憶體配置設定,可能也直接配置設定到永久代(一個極端的例子是年輕代根本就存不下)。
(3)年輕代
絕大多數的記憶體配置設定回收動作都發生在年輕代。如下圖所示, 年輕代被劃分為三個區域,原始區(Eden)和兩個小的存活區(Survivor),兩個存活區按功能分為From和To。絕大多數的對象都在原始區配置設定,超過一個垃圾回收操作仍然存活的對象放到存活區。
說明:年輕代裡面的對象經過多個回收周期依然存活的會自動晉升到年老代。年老代多個回收周期依然存活的會成為永久代。
3、JAVA虛拟機垃圾回收機制
(1)Minor GC
從年輕代空間(包括 Eden 和 Survivor 區域)回收記憶體被稱為 Minor GC。這一定義既清晰又易于了解。但是,當發生Minor GC事件的時候,當 JVM 無法為一個新的對象配置設定空間時會觸發 Minor GC,比如當 Eden 區滿了。是以配置設定率越高,越頻繁執行 Minor GC。
所有的 Minor GC 都會觸發“全世界的暫停(stop-the-world)”即停止應用程式的線程。
(2)Major GC vs Full GC
指發生在老年代的 GC,出現了 Major GC,經常會伴随至少一次的 Minor GC 。MajorGC 的速度一般會比 Minor GC 慢 10倍以上。
當發生Full GC時,也會觸發“全世界的暫停(stop-the-world)”即停止應用程式的線程。并且持續時間長。
二、Java排錯三劍客
1、jstack 檢視指定的java程序的線程棧的相關資訊
jstack [-l] <pid>
jstack -F [-m] [-l] <pid>
-l:long listings,會顯示額外的鎖資訊,是以,發生死鎖時常用此選項
-m:混合模式,既輸出java堆棧資訊,也輸出C/C++堆棧資訊
-F:當使用“jstack -l PID"無響應,可以使用-F強制輸出資訊
例子:
(1)檢視pid
ps aux|grep tomcat
root 2745 0.6 19.0 2333928 190144 pts/0 Sl 08:58 3:57 /usr/java/jdk1.8.0_144/jre/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start
root 9424 0.0 0.0 112648 960 pts/0 S+ 19:47 0:00 grep --color=auto tomcat
可以看到pid為 2745
(2)jstack -l 2745

2、jstat 輸出指定的java程序的統計資訊
jstat -help|-options
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
# jstat -options
-class:class loader 類加載統計
-compiler:JIT 編譯統計
-gc:gc
-gcnew:新生代
-gcold:老年代
-printcompilation JVM編譯方法統計
[<interval> [<count>]]
interval:時間間隔,機關是毫秒;
count:顯示的次數;
例子:
(1)jstat -class 2745 1000 1000 以秒為間隔顯示1000次,類加載統計
(2)jstat -gc 2745 1000 1000 可以看大GC和小GC的發生頻率。
S0C、S1C、S0U、S1U:Survivor 0/1區容量(Capacity)和使用量(Used)
EC、EU:Eden區容量和使用量
OC、OU:年老代容量和使用量
PC、PU:永久代容量和使用量
YGC、YGT:年輕代GC次數和GC耗時
FGC、FGCT:Full GC次數和Full GC耗時
GCT:GC總耗時
3、jmap Memory Map, 用于檢視堆記憶體的使用狀态
非常消耗資源,一般先把機器摘下,再執行指令
jmap [option] <pid> 檢視堆空間的詳細資訊:
jmap -heap <pid>檢視堆記憶體中的對象的數目:
jmap -histo <pid>
live:隻統計活動對象;
儲存堆記憶體資料至檔案中,而後使用jvisualvm或jhat進行檢視:
jmap -dump:<dump-options> <pid>
dump -options:
live dump only live objects; if not specified, all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
例子:jmap -dump:format=b,file=/app/dump 2745
cd /app
因為是二進制檔案不能直接看,需要轉換
jhat dump