《垃圾回收的算法與實現》——引用計數法

基本概念

  • 在對象中引入計數器(無符號整數),用於記錄有多少對象引用了該對象。
  • 經過增減計數器實現對內存的管理。
  • 分配對象時將計數器置1。
  • 更新引用時先對新指定的對象進行計數器加,然後纔對舊對象進行減。
  • 在對計數器作減法時,判斷其計數器是否等於0,等於0 表示爲垃圾,便可進行回收。
  • 在更新引用時就進行了垃圾的標記與回收,所以STW會很短並且當對象變垃圾時能立馬被回收。

優缺點

優勢

  1. 即刻回收垃圾,在更改引用時就知道該對象是否爲垃圾如果垃圾立馬進行回收(可是該操做會佔用用戶線程的時間片)
  2. STW短,回收垃圾不須要遍歷堆了。
  3. 不須要根據GC root遍歷。

缺點

  1. 計數器值增減頻繁。
  2. 計數器須要佔用不少位。
  3. 實現繁瑣,更新引用時很容易致使內存泄露。
  4. 循環引用沒法回收(最重要的缺點)

改進

延遲引用計數法

針對計數器增減頻繁html

  • 從根引用的指針變化不修改計數器,爲了使還存在引用的對象被回收,引入ZCT(Zero Count Table)記錄計數器爲0的對象(當爲0時不直接刪除而是加入到該表中)。
  • 分配塊時,先正常分配(應該也是經過空閒鏈表),若是分配失敗則從ZCT中找能夠真正的垃圾對象進行回收與分配。
  • 掃描ZTC表須要遍歷GC root,對全部GC root引用的計數器加1,然後遍歷ZTC,此時計數器爲0的即爲垃圾,最後對GC root引用對象減一(還原)。

Sticky引用計數法

針對計數器佔用不少位算法

因爲大多數對象的引用並不會不少,能夠減小計數器的位寬,當計數器溢出時有兩種處理方式:markdown

  1. 無論,對於溢出的對象再也不增減計數器。此時沒法判斷是否爲垃圾所以再也不關此對象,溢出的可能性很低因此是一個能夠考慮的解決辦法。
  2. 使用GC標記-清除算法,先把全部對象(==我以爲處理已溢出的就能夠?==)的計數器置0,然後遍歷GC root,可引用的將計數器置1,清除階段則清理那些計數器爲0的。

1位引用計數法

Sticky的極端例子post

  • 計數器只有1位,0表示只有一個引用(UNIQUE)1表示多引用(MULTIPLE)。
  • 更新引用時經過複製某個指針來更新。

==以爲有問題,怎麼找到能夠被複制的指針呢?指針是單鏈表,沒法經過對象找到其指針吧==線程

部分標記-清除算法

針對循環引用指針

  • 爲了解決循環引用不能被回收有采用在某些時候加入GC標記-清除算法,然而循環引用每每不多,效率很低。
  • 該方法是隻對可能存在循環引用的對象羣進行Sweep。
  • 對象被標記爲四種顏色,黑:不是垃圾,白:垃圾,灰:搜索過的對象,陰影:多是循環引用對象。上色採用兩位標記
  • 當刪除引用關係時,先自減,然後若是計數器爲0則回收該對象,不然將該對象置爲陰影並加入到hatch_queue
  • 當空閒鏈表沒法分配時將去hatch_queue中掃描是否存在循環垃圾可進行回收。
  • 遍歷取hatch_queue中對象分別作paint_gray、scan_gray和collect_white
  • paint_gray將對象置灰,然後將全部子對象計數器減1,並調用迭代paint_gray.
  • scan_gray將灰色中計數器爲0的對象置白,大於0的塗成黑色。
  • collect_white回收白色對象

轉載於:https://www.cnblogs.com/suolu/p/6649417.htmlhtm