1. 程式人生 > >java記憶體管理-記憶體回收

java記憶體管理-記憶體回收

java的記憶體回收主要分兩個部分:

1、判斷物件是否可以回收。

2、執行回收的過程。


判斷物件是否可以回收:

主要演算法有兩種

(1) 引用計數演算法

給物件中新增一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的物件就是不可能再被使用的。


這個演算法的有點就是簡單、容易實現,但是缺點也比較明顯,就是會出現迴圈引用:



(2)可達性分析演算法

通過一系列的稱為“GC Roots”的物件作為起始點,從這些節點開始進行向下搜尋,搜尋所走過的路徑成為引用鏈(Reference Chain),當一個物件到GC Roots沒有任何引用鏈相連(用圖論的話來說就是從GC Roots到這個物件不可達)時,則證明此物件是不可用的。這個演算法也是hotspot使用的演算法。



Java 語言中的 GC Roots可以是一下內容:
*在虛擬機器棧(棧幀中的本地變量表)中的引用的物件。
*在方法區中的類靜態屬性引用的物件。
*在方法區中的常量引用的物件。
*在本地方法棧中JNI(即一般說的Native方法)的引用的物件。


垃圾回收

主要有四個演算法

1、標記-清除演算法

演算法分為“標記”和“清除”兩個階段:首先標記出所有需要回收的物件,在標記完成後統一回收掉所有被標記的物件

標記-清除演算法的主要缺陷:標記清除之後會產生大量不連續的記憶體碎片




2、複製演算法

將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的記憶體用完了,就將還存活著的物件複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉

複製演算法的主要缺陷:將記憶體縮小為了原來的一半


3、標記-整理演算法

標記過程仍然與“標記-清除”演算法一樣,但後續步驟不是直接對可回收物件進行清理,而是讓所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體。

標記-整理演算法的主要缺陷:標記和整理階段必須停止執行執行緒




4、分代收集演算法

根據物件的存活週期的不同將記憶體劃分為幾塊。一般是把Java堆分為新生代和老年代,這樣就可以根據各個年代的特點採用最適當的收集演算法。

一般新生代使用複製演算法,老年代使用的是標誌整理演算法。

hotspot使用的是GC Roots 列舉 和 分代垃圾回收演算法,其中的難點就在於檢查範圍大,必須在快照中進行,時間敏感,也就是說要停止工作執行緒,但是不是每個時間都能停止工作執行緒去執行垃圾回收,所以就產生一個安全點和安全區的概念,這個概念本人還不怎麼理解,所以就暫不記錄。