7.6.5 拷貝回收器

拷貝回收器(Copying Garbage Collector)是一種常見的垃圾回收算法,通常用於實現新生代的垃圾回收。與標記-清掃式或標記並壓縮算法不同,拷貝回收器將堆內存分爲兩個區域:From區和To區。在每次垃圾回收時,它將存活的對象從From區拷貝到To區,並且清空From區,以便下一次垃圾回收時重複利用。以下是拷貝回收器的基本工作流程:

  1. 初始分配: 堆內存被分爲兩個相等大小的區域:From區和To區。一開始,From區是用來存放對象的,而To區是空的。

  2. 對象分配: 當程序需要分配新的對象時,會將對象分配到From區。From區用於存放新創建的對象。

  3. 垃圾回收: 當From區的空間不足時,觸發一次垃圾回收。垃圾回收器會遍歷From區中的所有對象,並且標記所有可達的對象。然後,它將所有可達的對象複製到To區,並且清空From區。

  4. 對象更新: 在拷貝過程中,所有被拷貝的對象的引用也需要更新。如果被拷貝的對象引用了其他對象,那麼引用將會指向To區中的對象。

  5. 區域交換: 當拷貝完成後,From區和To區的角色互換。即,To區成爲新的From區,From區成爲新的To區。這樣,下一次垃圾回收時,就會使用To區作爲新的From區。

通過拷貝回收器,可以解決新生代中的內存碎片化問題。因爲每次垃圾回收後,所有存活的對象都會被緊湊地複製到To區,而From區則被完全清空,因此不會出現內存碎片。拷貝回收器也相對簡單高效,因爲它只需要在From區進行垃圾回收,並且拷貝存活對象到To區,而不需要進行標記、清掃或者壓縮等複雜的操作。

--------------------------------------------------------------------

摘自編譯原理文章片段:

現在我們可以考慮這個算法本身了。第(2)行確保From 空間中的所有對象都還沒有新地址。在第(3)行中,我們初始化兩個指針 unscanned 和fee,使它們都指向 To 半空間的開始位置。指針fee 將總是指向 7o 半空間中空閒空間的起始位置。當我們往 " 空間加人對象時,那些地址低於unscanned的對象將處於已掃描狀態,而那些位於unscanned 和fee 之間的對象則處於待掃描狀態。因此,fee 總是在 uscunmed的前面。當後者追上前者時就表示不存在更多的待掃描對象了我們就完成了垃圾回收工作。請注意,我們是在T 空間中完成垃圾回收工作的,儘管在第(8)行中檢查的對象中的所有引用都是指向 From 空間的。

這段描述的是拷貝回收器的工作原理,具體來說,是在描述如何在To區域中完成垃圾回收工作,儘管待處理對象的引用都是指向From區域的情況。

讓我們逐句解釋:

  1. 第(2)行確保From空間中的所有對象都還沒有新地址。

    • 這句話指的是在垃圾回收開始之前,From空間中的所有對象都應該還沒有被拷貝到To空間中,它們的引用仍然指向From空間。

  2. 在第(3)行中,我們初始化兩個指針unscanned和fee,使它們都指向To半空間的開始位置。指針fee將總是指向To半空間中空閒空間的起始位置。

    • 這段描述說明了在初始化拷貝回收器時,兩個指針unscanned和fee被初始化爲指向To空間的起始位置,其中unscanned指向未掃描的位置,fee指向未使用的空間的起始位置。

  3. 當我們往"空間加人對象時,那些地址低於unscanned的對象將處於已掃描狀態,而那些位於unscanned和fee之間的對象則處於待掃描狀態。因此,fee總是在unscanned的前面。

    • 這句話解釋了在拷貝回收器工作期間,隨着對象被拷貝到To空間,unscanned指針會向後移動,將拷貝過的對象標記爲已掃描,而fee指針則始終指向未使用的空間的起始位置,確保待處理對象位於unscanned和fee之間。

  4. 當後者追上前者時就表示不存在更多的待掃描對象了,我們就完成了垃圾回收工作。

    • 當unscanned指針追上fee指針時,表示To空間中已經沒有更多待掃描的對象了,即所有存活對象都已經被拷貝到To空間,並且所有引用也已經更新爲指向To空間的地址,此時垃圾回收工作完成。

總體來說,這段描述了拷貝回收器如何在To空間中完成垃圾回收工作,並且解釋了unscanned和fee兩個指針在這個過程中的作用。儘管對象的引用指向From空間,但是拷貝回收器會將對象拷貝到To空間,並且更新所有引用爲指向To空間的地址。

 

---------------------------------------------------------------------------

摘自編譯原理文章片段:

第(4)行和第(5)行處理可以從根集訪問到的對象。請注意,因爲函數副作用,在第(5)行中對 LookupNeuwLocation 的某些調用會在 "中爲這些對象分配存儲塊,同時增加,fee 指針的值。因此,除非沒有被根集引用的對象(在這種情況下,整個堆區都是垃圾),當程序第一次運行到這裏時將進入第(6)行到第(10)行的循環。然後,這個循環掃描所有已經被加入到 To 空間中並處於待掃描狀態的對象。第(7)行處理下一個待掃描的對象。。在第(8)、(9)行,對於o中的每個引用,從它在From 半空間中的原值被翻譯爲在 To半空間中的值。

這段描述說明了在拷貝回收器的工作過程中,當處理根集引用到的對象時,可能會觸發新對象的分配,進而增加fee指針的值。我將逐句解釋:

  1. 第(4)行和第(5)行處理可以從根集訪問到的對象。

    • 這句話指的是拷貝回收器在處理根集引用到的對象時,執行的操作。根集是程序中的一組初始引用,通常包括全局變量、棧中的引用等。

  2. 因爲函數副作用,在第(5)行中對LookupNeuwLocation的某些調用會在中爲這些對象分配存儲塊,同時增加fee指針的值。

    • 這句話說明了在執行第(5)行中的某些操作時,可能會觸發函數LookupNeuwLocation的調用,這個函數會爲新對象分配存儲塊,並且增加fee指針的值。函數的副作用指的是除了返回值外,還會對其他變量或狀態產生影響。

  3. 除非沒有被根集引用的對象(在這種情況下,整個堆區都是垃圾),當程序第一次運行到這裏時將進入第(6)行到第(10)行的循環。

    • 這句話指的是在程序第一次運行到處理根集引用的代碼段時,如果沒有根集引用的對象,那麼整個堆區都被認爲是垃圾,垃圾回收工作就可以直接跳過。否則,程序將進入第(6)行到第(10)行的循環。

  4. 然後,這個循環掃描所有已經被加入到To空間中並處於待掃描狀態的對象。

    • 這句話指的是循環會掃描所有已經被加入到To空間中並處於待掃描狀態的對象,即unscanned和fee指針之間的對象。

  5. 第(7)行處理下一個待掃描的對象。

    • 這句話說明了循環中的第(7)行代碼的作用,即處理下一個待掃描的對象。在這個過程中,unscanned指針會向後移動。

  6. 在第(8)、(9)行,對於o中的每個引用,從它在From半空間中的原值被翻譯爲在To半空間中的值。

    • 這句話解釋了第(8)和(9)行代碼的作用,即更新對象中的引用,使其指向To半空間中對應的對象。由於對象已經被拷貝到To空間,所以需要更新引用。

  7. 請注意,因爲函數副作用,如果解釋下這句話。

    • 這句話強調了在處理引用更新時可能會發生的函數副作用,例如函數的調用可能會影響其他變量或狀態。在這個上下文中,函數的副作用可能會導致新對象的分配,進而增加fee指針的值。

7.6.6 四種垃圾收集器開銷的比較


Cheney 算法的優勢在於它不會涉及任何不可達對象。另一方面,拷貝垃圾回收器必須移動所有可達對象的內容。對於大型對象,或者那些經歷了多輪垃圾收集過程的生命週期長的對象而言,這個過程的開銷特別高。我們對本節給出的四種算法的運行時間進行總結。下面的每個估算都忽略了處理根集的開銷。
。基本的標記-清掃式算法(算法7.12):與堆區中存儲塊的數目成正比。
Baker 的標記-清掃式算法(算法7.14):與可達對象的數目成正比。#
基本的標記並壓縮算法(算法7.15):與堆區中存儲塊的數目和可達對象的總大小成正比。
。Cheney 的拷貝回收器(算法7.16):與可達對象的總大小成正比。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章