1. 程式人生 > >JAVA的垃圾回收機制(GC)

JAVA的垃圾回收機制(GC)

文章目錄

什麼是垃圾回收?

JVM有專門的垃圾回收器負責Java的記憶體管理,稱為GC(Garbage Collector)。負責分配記憶體、確保被引用的物件留在記憶體、回收不再被引用的物件,自動釋放記憶體。

哪些記憶體需要回收?何時?怎麼回收?(What?When?How?)

執行時資料區的程式計數器、虛擬機器棧、本地方法棧都隨執行緒的產生而產生、消滅而消滅。每一個棧幀分配多少記憶體編譯時可知,因此這些區域不需要回收。而Java堆和方法區則不一樣:類需要的記憶體不一樣,建立哪些物件也要執行期才知道,因此這部分記憶體是動態的,需要垃圾收集器回收。在堆中,尤其新生代,一次垃圾回收可以回收70%-95%的空間,而方法區的效率遠低於此。

如何判斷物件是否存活?

最簡單的是物件新增引用計數器,為0時則物件不再存活。此方法最主要的問題無法解決物件間的迴圈引用。
因此Java虛擬機器沒有使用此方法,而是使用"可達性分析演算法":
當一個物件到GC Roots沒有引用鏈相連的話,可以回收。
可以作為GC Roots的物件有:
虛擬機器棧中引用的物件;
方法區中類靜態屬性引用的物件;
方法區中常量引用的物件;
本地方法棧中JNI引用的物件。

垃圾回收有幾種演算法?

標記-清除演算法

先標記要回收的物件,標記完成後統一清除回收。
效率不高,並且會產生記憶體碎片。

複製演算法

將記憶體分兩塊,當一塊用完了,就把存活的物件拷貝到另一塊中,用完的那塊一次清理掉。
最典型的應用是對新生代的回收,新生代的物件98%都是“朝生夕死”的,商業虛擬機器都採用這種方法回收新生代。新生代的記憶體分為一個Eden區和兩個Survivor區(比例是8:1:1)。回收時,將Eden和Survivor區存活的物件複製到另一個Survivor區中,然後清理掉Eden區和Survivor區。前面說過,新生代的存活時間短,所以當垃圾回收時,可以回收掉90%的記憶體,存活的物件放入10%的Survivor中,所以比例8:1:1可以滿足要求。
如果Survivor區中不夠存放,那麼需要依賴其他記憶體(老年代)進行分配擔保,進入老年代。

標記-整理演算法

複製演算法不適用於老年代,老年代使用“標記-整理演算法”。整理階段會將存活的物件向一端移動,已防止記憶體碎片

介紹垃圾收集器?

垃圾收集器是記憶體回收的具體實現。

Serial GC

最古老的單執行緒垃圾收集器,必須暫停所有其他的工作執行緒,會有Stop-The-World問題。 用於Client模式。

ParNew GC

Serial GC的多執行緒版本,可與CMS配合

CMS(Concurrent Mark Sweep)

併發收集器,減少停頓時間。包括初識標記、併發標記、最終標記、篩選回收。

Parrallel GC

新生代和老年代都是並行進行的,適用吞吐量高的Server模式。

G1 GC(JAVA9預設的垃圾回收器)

兼顧吞吐量和停頓時間的GC。

指令檢視

jmap -heap 程序號
程序號可檢視Java程序得到
ps -ef|grep java

參考資料

《深入理解Java虛擬機器:JVM高階特性與最佳實踐(第2版)》 周志明 著
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/toc.html
http://blog.jobbole.com/109170/
https://docs.oracle.com/javase/9/gctuning/toc.htm