天天看點

Java垃圾回收機制算法

finalize方法作用

Java技術使用finalize()方法在垃圾收集器将對象從記憶體中清除出去前,做必要的清理工作。這個方法是由垃圾收集器在确定這個對象沒有被引用時對這個對象調用的。它是在Object類中定義的,是以所有的類都繼承了它。子類覆寫finalize()方法以整理系統資源或者執行其他清理工作。finalize()方法是在垃圾收集器删除對象之前對這個對象調用的。

public class Test {
	public static void main(String[] args) {
		Test test = new Test();
		test = null;
		System.gc(); // 手動回收垃圾
	}

	@Override
	protected void finalize() throws Throwable {
		// gc回收垃圾之前調用
		System.out.println("垃圾回收機制...");
	}
}
           

1.引用計數法

(由于引用計數法的循環引用這個缺陷,是以基本不用該算法)

1.1概述

給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器都為0的對象就是不再被使用的,垃圾收集器将回收該對象使用的記憶體。

1.2優缺點

優點:

引用計數收集器可以很快的執行,交織在程式運作中。對程式需要不被長時間打斷的實時環境比較有利。

缺點:

無法檢測出循環引用。如父對象有一個對子對象的引用,子對象反過來引用父對象。這樣,他們的引用計數永遠不可能為0.而且每次加減非常浪費記憶體。

根搜尋算法

概念

根搜尋算法的基本思路就是通過一系列名為”GC Roots”的對象作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鍊(Reference Chain),當一個對象到GC Roots沒有任何引用鍊相連時,則證明此對象是不可用的。

這個算法的基本思想是通過一系列稱為“GC Roots”的對象作為起始點,從這些節點向下搜尋,搜尋所走過的路徑稱為引用鍊,當一個對象到GC Roots沒有任何引用鍊(即GC Roots到對象不可達)時,則證明此對象是不可用的。

那麼問題又來了,如何選取GCRoots對象呢?在Java語言中,可以作為GCRoots的對象包括下面幾種:

(1). 虛拟機棧(棧幀中的局部變量區,也叫做局部變量表)中引用的對象。

(2). 方法區中的類靜态屬性引用的對象。

(3). 方法區中常量引用的對象。

(4). 本地方法棧中JNI(Native方法)引用的對象。

下面給出一個GCRoots的例子,如下圖,為GCRoots的引用鍊。

Java垃圾回收機制算法

(解釋:gc會回收user3和user5,因為它們沒有依賴gcroot,而user1,2,4,6都分别直接或間接地依賴gcroot(解析:gcroot包含哪些對象,如上文已詳述))

從上圖,reference1、reference2、reference3都是GC Roots,可以看出:

reference1-> 對象執行個體1;

reference2-> 對象執行個體2;

reference3-> 對象執行個體4;

reference3-> 對象執行個體4 -> 對象執行個體6;

可以得出對象執行個體1、2、4、6都具有GC Roots可達性,也就是存活對象,不能被GC回收的對象。

而對于對象執行個體3、5直接雖然連通,但并沒有任何一個GC Roots與之相連,這便是GC Roots不可達的對象,這就是GC需要回收的垃圾對象。

2.複制算法

(主要應用在新生代)

S0和s1将可用記憶體按容量分成大小相等的兩塊,每次隻使用其中一塊,當這塊記憶體使用完了,就将還存活的對象複制到另一塊記憶體上去,然後把使用過的記憶體空間一次清理掉。這樣使得每次都是對其中一塊記憶體進行回收,記憶體配置設定時不用考慮記憶體碎片等複雜情況,隻需要移動堆頂指針,按順序配置設定記憶體即可,實作簡單,運作高效。

複制算法的缺點顯而易見,可使用的記憶體降為原來一半。

複制算法用于在新生代垃圾回收

3.标記清除算法

*(主要應用在老年代)

标記-清除(Mark-Sweep)算法顧名思義,主要就是兩個動作,一個是标記,另一個就是清除。

标記就是根據特定的算法(如:引用計數算法,可達性分析算法等)标出記憶體中哪些對象可以回收,哪些對象還要繼續用。

标記訓示回收,那就直接收掉;标記訓示對象還能用,那就原地不動留下。

Java垃圾回收機制算法

缺點

1.标記與清除沒有連續性效率低;

2.清除之後記憶體會産生大量碎片;

是以碎片這個問題還得處理,怎麼處理,看标記-整理算法。

4.标記-壓縮算法

(主要應用在老年代)

标記壓縮法在标記清除基礎之上做了優化,把存活的對象壓縮到記憶體一端,而後進行垃圾清理。(java中老年代使用的就是标記壓縮法)

5.分代收集算法

根據記憶體中對象的存活周期不同,将記憶體劃分為幾塊,java的虛拟機中一般把記憶體劃分為新生代和年老代,當新建立對象時一般在新生代中配置設定記憶體空間,當新生代垃圾收集器回收幾次之後仍然存活的對象會被移動到年老代記憶體中,當大對象在新生代中無法找到足夠的連續記憶體時也直接在年老代中建立。

對于新生代和老年代來說,新生代回收頻率很高,但是每次回收耗時很短,而老年代回收頻率較低,但是耗時會相對較長,是以應該盡量減少老年代的GC.

Minor GC和Full GC差別

繼續閱讀