1. 程式人生 > >JAVA虛擬機垃圾回收機制和JAVA排錯三劍客

JAVA虛擬機垃圾回收機制和JAVA排錯三劍客

jvm 垃圾 回收機制

一、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

-classclass loader 類加載統計

-compilerJIT 編譯統計

-gcgc

-gcnew新生代

-gcold老年代

-printcompilation JVM編譯方法統計

[<interval> [<count>]]

interval時間間隔,單位是毫秒;

count顯示的次數;

例子:

(1)jstat -class 2745 1000 1000 以秒為間隔顯示1000次,類加載統計

技術分享圖片

(2)jstat -gc 2745 1000 1000 可以看大GC和小GC的發生頻率。

技術分享圖片

S0CS1CS0US1USurvivor 0/1區容量(Capacity)和使用量(Used)

ECEUEden區容量和使用量

OCOU年老代容量和使用量

PCPU永久代容量和使用量

YGCYGT年輕代GC次數和GC耗時

FGCFGCTFull GC次數和Full GC耗時

GCTGC總耗時

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

ss -ntl 會監聽7000端口,可以在瀏覽器查看

技術分享圖片


JAVA虛擬機垃圾回收機制和JAVA排錯三劍客