GC判定與回收演算法+java物件引用型別

5ingwings發表於2018-03-28

java物件引用型別

強引用: 如 A a = new A();

軟引用: 記憶體不夠,可以回收
弱引用: 只生存到下一次GC

虛應用:如果一個物件僅持有虛引用,並不會生成例項,它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。虛引用主要用來跟蹤物件被垃圾回收器回收的活動。


GC垃圾回收的判定方法(判定是否該回收)

1 引用計數法

即 堆中每個物件(不是引用)都有一個引用計數器。當一個物件被建立並初始化賦值後,該變數計數設定為1。每當有一個地方引用它時,計數器值就加1,當引用結束,計數器則減1,當計數器值為0時,就可以進行垃圾回收。若該物件被回收了,則它引用的物件計數器也都減去1

該方法 簡單,高效,但是 如果 遇到 兩個物件相互引用,而這兩個物件又很久沒有使用時,仍然不能被回收。

2 根搜尋演算法

從 GCRoot物件為起點,尋找可訪問的引用變數(注意不是物件),若物件沒有被任何引用變數相連,則該物件可以回收。

GCRoot物件:

(1) 所有正執行的執行緒上的引用變數

(2) Native方法引用的物件

(3) 所有執行的方法中的引用物件


注意: 若發現了某個物件可被回收,並不是立即回收,而是會先看他有沒有執行finalize()方法 若在finalize方法中進行了該物件的相關引用,則不會被回收


回收演算法

1 標記-清除法

首先標記出所需回收的物件,在標記完成後統一回收掉所有被標記的物件 

但是這樣,釋放出來的記憶體,會產生很多無法利用的記憶體碎片

2 標記-整理法

也是先標記,但是清除的時候 未被回收的物件會向著某一端移動整理,然後清空掉端以外的物件,這樣記憶體碎片就會減少很多,但是這樣比較耗時,要計算物件新的儲存位置的引用。

3 複製法:

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

這個方法比較佔用空間,使空間利用率減少了一半。適用於物件存活率較低的,否則大量物件又要複製過去

4 分代收集法:

主要分為 新生代,年老代,和持久代。不同代會採用不同的回收演算法

(1) 新生代 主要有 Eden區,FromSpace,ToSpace區

當Eden區滿了,發起一次GC,則會通過複製演算法 將未被回收的物件賦值到FromSpace區,清空Eden區域,新物件再加入Eden區

若FromSpace區也滿了,發起一次GC,再將 Eden和FromSpace區的物件複製到ToSpace區,並且清空Eden和FromSpace區

若ToSpace區也滿了,就會將存活物件複製到年老區。

若是老年代也滿了就會觸發一次Full GC,也就是新生代、老年代都觸發回收。

 (2) 年老代

年老代中存放的都是一些生命週期較長的物件。記憶體比新生代也大很多

(3) 持久代

 用於存放靜態檔案(class類、方法)和常量等,也是會被回收的,主要回收不再使用的類和常量。

java SE8以後不再有持久代,而是元空間


新物件一般放入新生代,大物件直接放入年老代,而全域性變數則放入持久代中


參考:https://www.jianshu.com/p/5261a62e4d29


相關文章