跳轉至內容

程式語言導論/垃圾回收

來自華夏公益教科書,開放的書籍,開放的世界

垃圾回收

[編輯 | 編輯原始碼]

垃圾回收 (GC) 是一種自動記憶體管理的形式。垃圾回收器,或簡稱收集器,試圖回收垃圾,即程式不再使用的物件所佔用的記憶體。垃圾回收通常被認為是手動記憶體管理的相反,手動記憶體管理需要程式設計師指定要釋放並返回到記憶體系統的物件。垃圾回收與其他記憶體管理技術一樣,可能會佔用程式總處理時間的很大一部分,因此會對效能產生重大影響。

在本節中,我們將描述三種形式的垃圾回收。


標記-清除

[編輯 | 編輯原始碼]
樸素的標記-清除方法在包含八個物件的堆上執行。箭頭代表物件引用。圓圈代表物件本身。物件 #1、#2、#3、#4 和 #6 從根集被強引用。另一方面,物件 #5、#7 和 #8 既沒有從根集直接引用也沒有間接引用;因此,它們是垃圾。

標記-清除收集器試圖找到活動堆連結,並標記那些可達的塊。然後它遍歷堆,並將未標記的空閒塊返回到空閒池。

標記-清除方法是第一個已知的垃圾回收策略。在此方法中,垃圾回收器從稱為根集的點(程式中易於識別的物件集)開始掃描程式,並嘗試從該點到達其他物件。收集器重複此掃描,直到它無法找到任何更多可達物件。每當找到一個物件時,就會設定其“正在使用”位。收集器完成標記物件後,它遍歷整個堆,釋放那些沒有設定“正在使用”位的物件。

此方法有幾個缺點,最顯著的是在收集過程中必須暫停整個系統。這會導致程式定期(並且通常不可預測地)“凍結”,使即時和時間關鍵型應用程式無法實現。

複製收集

[編輯 | 編輯原始碼]

複製收集收集器中,記憶體被分成兩部分;一次只使用其中一部分。當使用的一半已滿時,將使用的塊複製到另一個位置,並擦除舊的位置。

此方法有兩個主要缺點。首先,它必須停止程式的執行才能將物件從堆的一部分移動到另一部分。其次,它必須更改程式物件指向的地址。這涉及更改程式中變數的值。在像 C 這樣的語言中,你將物件的地址儲存在一個整數中,這使得垃圾回收器更難確定哪些程式變數儲存了物件的地址。

複製收集的最大優勢在於,如果程式使用的記憶體大小小於正在使用的堆一半的大小,則無需複製,從而避免停止程式和更改物件的地址。

引用計數

[編輯 | 編輯原始碼]

引用計數收集器中,每個塊都有一個指向它的堆連結計數器。當複製堆連結時,此計數器會增加,當丟棄連結時,它會減少。當計數器變為零時,該塊將被釋放。與跟蹤垃圾回收相比,引用計數保證物件在變得不可達時立即被銷燬。

引用計數的最大優勢在於程式不需要停止來執行垃圾回收。最大的缺點是

  • 使用額外的空間來儲存引用計數器。
  • 如果兩個或多個物件相互引用,它們可以建立一個迴圈,其中任何一個物件都不會被回收,因為它們的相互引用永遠不會讓它們的引用計數變為零。
華夏公益教科書