《垃圾回收的算法與實現》讀書筆記

  • 概述

    • 垃圾回收算法的評價標準:

      1. 吞吐量:
        程序運行時間/(程序運行時間+垃圾回收時間)純屬個人理解

      2. 暫停時間

      3. 堆使用效率
        比如複製算法,就只能使用一半的空間

      4. 訪問的局部性
        利用空間局部性原理,將具有引用關係的對象放在一起.比如複製算法會根據引用關係重排對象.

  • 標記-清除算法

    從GC-ROOT開始標記存活對象,然後回收對象,回收對象就是把對象作爲分塊,連接到被稱爲“空
    閒鏈表”的單向鏈表.重新分配內存的時候搜索空閒鏈表並尋找大小合適的分塊。

    • 優點

      1. 實現簡單
      2. GC 標記 - 清除算法因爲不會移動對象,所以非常適合搭配保守式 GC 算法
    • 缺點

      1. 碎片化
      2. 分配速度慢
      3. 與寫時複製不兼容(因爲要給存活對象標記,產生大量對象的複製)
    • 優化點

      1. 多個空閒鏈表(原來只用一個鏈表,現在根據對象塊的大小分成多個鏈表,根據要分配的長度找到對應的那一個鏈表)
      2. BiBOP法(把堆分割成固定大小的塊,讓每個塊只能配置同樣大小的對象。這就是 BiBOP法)
      3. 位圖標記(解決寫時複製不兼容,原先在對象頭裏做標記,現在位圖表格做標記)
      4. 延遲清除法(在分配時直接調用 lazy_sweep() 函數,進行清除操作。如果它能用清除操作來分配分塊,就會返回分塊;如果不能分配分塊,就會執行標記操作。)
  • 引用計數法

    • 優點

      1. 可即刻回收垃圾(在引用計數法中,每個對象始終都知道自己的被引用數,當被引用數的值爲 0 時,對象馬上就會把自己作爲空閒空間連接到空閒鏈表)
      2. 最大暫停時間短
      3. 沒有必要沿指針查找
    • 缺點

      1. 計數器值的增減處理繁重
      2. 計數器需要佔用很多位(用於引用計數的計數器最大必須能數完堆中所有對象的引用數。打個比方,假如我們用的是 32 位機器,那麼就有可能要讓 2 的 32 次方個對象同時引用一個對象。)
      3. 實現煩瑣複雜(引用計數的算法本身很簡單,但事實上實現起來卻不容易)
      4. 循環引用無法回收
    • 優化點

      1. 合併型引用計數法(把注意力放在某一時期最初和最後的狀態上,在該期間內不進行計數器的增減。這就是合併型引用計數法(Coalesced Reference Counting)。在合併型引用計數法中,即使指針發生改動,計數器也不會增減。指針改動時的信息會被註冊到更改緩衝區(Modified Buffer)。)
      2. Sticky引用計數法(用來減少計數器位寬只使用五位.減少意味着引用計數值可能會溢出. 處理溢出的方法:1.放任不管,因爲很多對象一生成馬上就死了,也就是說,在很多情況下,計數器的值會在 0 到 1 的範圍內變化,鮮少出現五位計數器溢出這樣的情況,即便是溢出,也說明這個對象很重要,其將來成爲垃圾的可能性也很低 2.使用 GC標記 -清除算法進行管理)
      3. 部分標記-清除算法(用於解決依賴循環問題.大致思路:將可能產生依賴循環的對象羣使用標記清除算法,其他地方使用引用計數算法。那麼我們怎麼判斷可能產生依賴循環的對象羣呢? 我們可以判斷當根引用關係清除後,引用計數不爲0,那麼該對象羣可能產生依賴循環)
  • 複製算法

    • 優點

      1. 優秀的吞吐量
      2. 可實現高速分配(GC 複製算法不使用空閒鏈表。這是因爲分塊是一個連續的內存空間。因此,調查這個分塊的大小,只要這個分塊大小不小於所申請的大小,那麼移動 $free 指針就可以進行分配了。比起 GC 標記 - 清除算法和引用計數法等使用空閒鏈表的分配,GC 複製算法明顯快得多。大家想一下,使用空閒鏈表時爲了找到滿足要求的分塊,需要遍歷空閒鏈表對吧?最壞的情況就是我們不得不從空閒鏈表中取出最後一個分塊,這樣就要花大把時間把所有分塊都調查一遍。)
      3. 不會發生碎片化
      4. 與緩存兼容(通過壓縮來把有引用關係的對象安排在堆中較近的位置)
    • 缺點

      1. 堆使用效率低下
      2. 不兼容保守式 GC算法
      3. 遞歸調用函數(複製某個對象時要遞歸複製它的子對象。因此在每次進行復制的時候都要調用函數,由此帶來的額外負擔不容忽視。大家都知道比起這種遞歸算法,迭代算法更能高速地執行.此外,因爲在每次遞歸調用時都會消耗棧,所以還有棧溢出的可能)
    • 優化點

      1. 使用迭代複製
      2. 多空間複製算法(GC 複製算法最大的缺點是隻能利用半個堆。這是因爲該算法將整個堆分成了兩半,每次都要騰出一半。那麼把堆再作細分會如何呢?舉個例子,我們不把堆分成 2 份,而是分成 10 份,其中需要拿出 2 塊空間分別作爲 From 空間和 To 空間來執行 GC 複製算法。反正無論如何都要空出 1 塊空間來當 To 空間,那我們就把這個額外負擔降到整體的 1/10 就行了。接下來,我們必須用別的方法對剩下的 8 塊空間執行 GC。在這裏 GC 標記 - 清除算法又登場了。)
  • 標記-整理算法

    • 優點

      1. 可有效利用堆
    • 缺點

      1. 壓縮花費計算成本
  • 分代垃圾回收

    • 記錄集

      記錄集被用於高效地尋找從老年代對象到新生代對象的引用(個人理解應該就是card table)
    • 倖存空間滿了怎麼辦?

      通常的 GC 複製算法把空間二等分爲 From 空間和 To 空間,即使 From 空間裏的對象都還
      活着,也確保能把它們收納到 To 空間裏去.To 倖存空間必須收納 From 倖存空間以及生成空間中的活動對象。From 倖存空間和生存空間的點大小比 To 倖存空間大,所以如果活動對象很多,To 倖存空間就無法容納下它們。當發生這種情況時,穩妥起見只能把老年代空間作爲複製的目標空間。當然,如果頻繁發生這種情況,分代垃圾回收的優點就會淡化。
    • 優點

      1. 吞吐量得到改善(“很多對象年紀輕輕就會死”這一法則雖然是經驗之談,不過還是適用於大多數情況的。以這個法則爲前提,新生代 GC 只將剛生成的對象當成對象,這樣一來就能減少時間上的消耗。)
    • 優化點

      1. 多代垃圾回收(分代垃圾回收將對象分爲新生代和老年代,通過儘量減少從新生代晉升到老年代的對象,來減少在老年代對象上消耗的垃圾回收的時間。基於這個理論,大家可能會想到分爲 3 代或 4 代豈不更好?這樣一來能晉升到最老一代的對象不就更少了嗎?這種方法就叫作多代垃圾回收.在這個方法中,除了最老的那一代之外,每代都有一個記錄集。X 代的記錄集只記錄來自比 X 老的其他代的引用。分代數量越多,對象變成垃圾的機會也就越大,所以這個方法確實能減少活到最老代的對象。)
  • 增量式垃圾回收

    簡單來說就是垃圾回收線程與工作線程交替執行.

    • 優點和缺點

      1. 縮短最大暫停時間
      2. 降低了吞吐量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章