垃圾回收的引用計數器演算法詳解

antzone發表於2018-06-03

本章節結合圖示介紹一下垃圾回收的引用計數演算法,需要的朋友可以做一下參考。

關於標記清除演算法可以參閱垃圾回收的標記清除演算法詳解一章節。

一.基本概念:

為每個物件增加一個欄位記錄被引用的次數,並由執行時跟蹤和更新引用的總數。

看如下程式碼例項:

[JavaScript] 純文字檢視 複製程式碼
var antzone = new Antzone("螞蟻部落");
var obj = antzone;

上面的程式碼中,我們例項化一個物件,並將其賦值給變數antzone,這個時候antzone引用了物件,計數器的值為1。

然後我將antzone賦值給變數obj,這時候已經有兩個變數引用物件了,所以計數器的值變為2。

圖示如下:

a:3:{s:3:\"pic\";s:43:\"portal/201704/10/130413d9gjris86urkik9i.jpg\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

圖示1,計數器的值為1。

a:3:{s:3:\"pic\";s:43:\"portal/201704/10/130440qy5dwz77emyq5dnw.jpg\";s:5:\"thumb\";s:0:\"\";s:6:\"remote\";N;}

圖示2,計數器的值為2。

由上面的程式碼可以看出,引用型別每次賦值都需要執行時更新計數器,執行時的更新程式碼可能如下:

[JavaScript] 純文字檢視 複製程式碼
if(antzone != obj){
  if (antzone != null)
    --antzone.refCount;
  antzone = obj;
  if (antzone != null)
    ++antzone.refCount;
}

二.計數器演算法優點:

此演算法的一大優點是無需等待記憶體耗盡再執行垃圾回收操作,其可以在賦值操作的同時,檢查計數器是否為0,如果是的話就可以立即回收;執行時的程式碼可能如下:

[JavaScript] 純文字檢視 複製程式碼
if (antzone != obj) {
  if (antzone != null)
    if (--antzone.refCount == 0)
      heap.Release(antzone);
 
  antzone = obj;
  if (antzone != null)
    ++antzone.refCount;
}

三.計數器演算法的缺點:

此演算法不能解決迴圈引用的問題,如下圖,構造了一個列表,將最後一個元素的next屬性指向第一個元素,即引用第一個元素,從而構成迴圈引用;這個時候如果我們將列表的頭head賦值為null,此時列表的各個元素的計數器都不為0,同時我們也失去了對列表的引用控制,從而導致列表元素不能被回收。

aid[410]

四.引用計數演算法的特點:

(1).需要單獨的欄位儲存計數器,增加了儲存空間的開銷。

(2).每次賦值都需要更新計數器,增加了時間開銷。

(3).垃圾物件便於辨識,只要計數器為0,就可作為垃圾回收。

(4).及時回收垃圾,沒有延遲性。

(5).不能解決迴圈引用的問題。

相關文章