天天看點

Reference Counting Garbage Collector 引用計數算法垃圾回收器

引用計數算法(Reference Counting)

垃圾回收的困難不在于 實際回收垃圾的過程,而是在于在哪些地方找到垃圾。當一個對象不在被引用時候 則這個對象被認為是可以被回收的。

算法描述:

在每個對象中有個一個字段refCount 記錄該對象被引用的次數,refCount是在java program 中不能被通路的,隻是可以被jvm 修改或者更新。

例如:

Object p = new Integer (57);

當建立一個Integer 類的執行個體,隻有一個變量p 指向這個對象,因為這個引用計數refCount=1

Reference Counting Garbage Collector 引用計數算法垃圾回收器

接着考慮下面的語句:

Object p = new Integer (57);

Object q = p;

這個語句隻是建立了一個integer 執行個體,p和q 都指向同一個對象,因為 這個執行個體的

refCount =2

總的來說,每次一個引用變量指派給另外一個變量時候,總是有必要更新幾個引用計數。假定p和q 都是引用變量,下面的指派

p = q;

在jvm 中将會實作成如下僞代碼:

if (p != q)

{

    if (p != null)

--p.refCount;

    p = q;

    if (p != null)

++p.refCount;

}

假如p,q初始化如下:

Object p = new Integer (57);

Object q = new Integer (99);

如圖a所描述的,構造了2個integer 執行個體,每個執行個體的refCount=1/

接下來,我們把p=q。

如圖b所描述的,在指派之後,p和q都指向了同一個對象,這個對象的refCount=2,而對Integer(57)這個對象的引用已經變成了0,這隻是gc去回收這個對象。

Reference Counting Garbage Collector 引用計數算法垃圾回收器

引用計數的開銷在兩個方面:

A:每個對象需要一個特殊的refCount 字段,在每個對象中 需要為這個字段配置設定額外的存儲空間

B:每次一個引用被指派給另外一個引用,這個refCount 就必須用上面的代碼進行調整,這明顯增加了指派語句的執行時間。

引用的計數算法的優點:

垃圾回收器很容易定位出需要回收的對象,并且并不需要等到沒有足夠的空間才啟動垃圾回收,當一個對象的refCount=0時,我們可以立即啟動垃圾回收。

例如 p=q

if (p != q)

{

    if (p != null)

if (--p.refCount == 0)

    heap.release (p);

    p = q;

    if (p != null)

++p.refCount;

}

用上述方法,垃圾将會被增量回收。

B:指向複雜對象:

例如:

Object p = new Association (new Integer (57), new Integer (99));

圖a描述了Object p = new Association (new Integer (57), new Integer (99));

這個語句執行完之後的記憶體内從。

Association  執行個體的引用數量refCount=1,因為之後一個變量p指向它。

相似的兩個integer執行個體的refCount =1,因為之後一個Association 執行個體指向它們。

        圖:當一個對象指向另一個對象的引用計數

Suppose we assign the value null to the variable p.

假定我們将p=null,如圖b所描述,association執行個體的refCount=0,這個association執行個體就變得可以被回收了。

Association 這個執行個體會一直存在直到gc開始回收Association 。圖d

描述了當Association 被gc時,,gc調整Association 執行個體引用的refCount 。經過調整之後 ,這兩個Intege 對象的refCount=0也可以被gc.

Reference Counting Garbage Collector 引用計數算法垃圾回收器

C:Reference Counting 算法失效:

如圖a所示循環的單連結清單,head 變量指向單連結清單的頭,并且這個單連結清單的最後一個元素也指向單連結清單的頭。 因為對于第一個元素的refCount=2,在連結清單中的其他元素的refCount=1

Reference Counting Garbage Collector 引用計數算法垃圾回收器

Figure: Why reference counting fails.

接下來,我們把head變量的值設定為null,head=null. 如圖b所表示,連結清單的第一個元素的refCount減少了因為head變量不在指向它,但是它的refCount !=0,因為連結清單的最後一個元素指向連結清單的第一個元素。

  現在我們遇到一個問題:在連結清單中的所有元素的refCount !=0,因而他們不會給gc.但是對于LinkedList 對象沒有外部引用,LinkedList對象裡的元素實際上是要被回收的。

總的來說,引用計數算法在碰到循環引用時候将不會奏效。但是JAVA 對于循環結構的建構是不會預防的。是以,引用計數算法對于複雜對象來說本身不是一個适合的垃圾回收模式。但是對于那些不指向其他對象的簡單對象,這個是一個非常有用技巧。