1. 程式人生 > >Java中的GC(Garbage Collection)

Java中的GC(Garbage Collection)

1、如何判斷是否是要回收的物件?

1)引用計數演算法:給物件新增一個計數器,每當有一個引用它時,計數器值加1;當引用失效時,計數器值減1。當計數器減為0時,說明該物件不能再被使用,此時該物件就可以被回收。

缺點:當有迴圈引用時,會一直得不到回收,例如變數a和變數b之間互相引用,形成迴圈引用。

2)可達性分析演算法:通過一系列的稱為“GC Roots”的物件為起點,從這些起點遍歷,走過的路徑稱為引用鏈(Reference Chain)。當一個物件無法通過引用鏈到達時,該物件就是可被回收的。

補充:在Java語言中,可被當做GC Roots的物件包括:

1)虛擬機器棧(棧幀中的本地變量表)中引用的物件;

2)方法區中類靜態屬性引用的物件;

3)方法區中常量引用的物件

2、垃圾回收演算法

1)標記-清除演算法(Mark-Sweep:兩個階段,“標記”和“清除”:首先標記出所有需要回收的物件,在標記完後統一回收所有被標記的物件。

缺點:標記和清除的效率都不高;多次標記清除後,會產生較多的不連續的記憶體碎片,導致在大的物件到來時,無法找到足夠的連續記憶體而導致垃圾收集。

2)複製演算法(Copying:將記憶體分為大小一樣的兩塊,每次只是用其中一塊,當使用中的這塊記憶體存不下物件時,會發生複製。將可用物件複製到另一個空閒記憶體上(順序存放),再將之前的記憶體中的物件全部清除。

缺點:記憶體利用率不到一半,太浪費;在物件存活率高的時候,效率明顯下降

3)標記-整理演算法(Mark-Compact:類似於標記-清除演算法,不同的是不直接清除可回收物件,而是將可用物件都移動到一端,然後將其它部分存在的可回收物件清除。

4)分代收集演算法(Generational Collection:根據物件存活週期將記憶體分為不同的幾塊。例如Java中,堆被分為新生代和老生代,新生代採用上面的複製演算法老生代採用上面的標記-清理演算法或者標記-整理演算法。

3、擴充套件

1)垃圾收集器關注的是Java的堆記憶體

2)虛擬記憶體技術:在記憶體使用不足時,可以將不常用的資料儲存到磁碟中,待到使用到這些資料時,再從磁碟中讀取。這時,就將使用的磁碟當成記憶體看待。

3)新生代中物件的特點:IBM研究發現,新生代中的物件98%是要被回收的,為此將記憶體空間劃分為8:1:1,8為Eden(伊甸園區),1為Survivor(倖存區)

在使用時,只是使用其中的Eden和一個Survivor,當發生回收時,將可用物件複製到那塊空閒的Survivor,完成後清理Eden和之前使用的Survivor。這樣記憶體浪費的就較少。

4)新生代/老生代:一般剛創建出來的物件是放入新生代中,在GC15次(預設次數)後,還沒有被回收的物件,就會進入老生代。

發生了老生代的記憶體擔保機制(新生代儲存不下,就可能儲存到老生代),也會將物件放入老生代

5)新生代中的物件在每次GC時,會有大量的物件被回收;而老生代中物件的存活率較高,並且較少發生GC。

新生代的GC:Minor GC

老生代的GC:Major GCFull GC,即新生代也會被觸發GC)

6)GC調優的目的是減少Full GC

4、GC收集器

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

新生代收集器

1)Serial收集器:單執行緒,在進行收集時,必須停止其它執行緒;

2)ParNew收集器:多執行緒的Serial收集器,使用複製演算法,也必須停止其它執行緒後才進行收集。除了Serial外,只有ParNew可以與CMS一起配合使用;

3)Parallel Scavenge收集器:並行的收集器,但關注點是:吞吐量(Throughput),而其它收集器關注的是減少使用者的停頓時間;最大特點以下介紹的GC自適應的調節策略

擴充套件:GC自適應的調節策略(GC Ergonomics:通過設定引數,可以讓虛擬機器自己根據系統執行情況動態的調整記憶體使用策略,達到動態的提供合適的停頓時間或最大的吞吐量。

老生代收集器

1)Parallel Old收集器:Parallel Scavenge的老生代版本,使用的是標記-整理演算法;

2)CMS(Concurrent Mark Sweep)收集器:一種以獲取最短回收停頓時間的為目標的收集器。基於標記-清理演算法。整個收集過程包括四個:初始標記(CMS initial mark)、併發標記(CMS concurrent mark)、重新標記(CMS remark)、併發清除(CMS concurrent sweep)。

其中初始標記、重新標記需要停頓使用者執行緒,但停頓時間很短

GI收集器:沒有區分新舊代,而是將整個堆分為若干個小區塊,其中新建物件在Eden Space中;回收後倖存物件在Survivor Space中;多次回收依舊存活的物件在Old Generation中。