Java垃圾回收器的工作原理

1. 引用計數 (Reference Counting)

引用計數是一種簡單但速度很慢的垃圾回收技術,從未被應用到任何一種Java虛擬機實現中。

引用計數方式最基本的形態就是讓每個被管理的對象與一個引用計數器關聯在一起,該計數器記錄著該對象當前被引用的次數,每當創建一個新的引用指向該對象時其計數器就加1,每當指向該對象的引用失效時計數器就減1。當該計數器的值降到0就認為對象死亡。每個計數器只記錄了其對應對象的局部信息——被引用的次數,而沒有(也不需要)一份全局的對象圖的生死信息。由于只維護局部信息,所以不需要掃描全局對象圖就可以識別并釋放死對象;但也因為缺乏全局對象圖信息,所以無法處理循環引用的狀況。更高級的引用計數實現會引入“弱引用”的概念來打破某些已知的循環引用。

2. 停止-復制(stop-and-copy)

將現有的內存空間分為兩快,每次只使用其中一塊,在垃圾回收時將正在使用的內存中的存活對象復制到未被使用的內存塊中,之后,清除正在使用的內存塊中的所有對象,交換兩個內存的角色,完成垃圾回收。

如果系統中的垃圾對象很多,復制算法需要復制的存活對象數量并不會太大。因此在真正需要垃圾回收的時刻,復制算法的效率是很高的。又由于對象在垃圾回收過程中統一被復制到新的內存空間中,因此,可確?;厥蘸蟮膬却婵臻g是沒有碎片的。該算法的缺點是將系統內存折半。

3. 標記-清除(mark-and-sweep)

標記-清除算法將垃圾回收分為兩個階段:標記階段和清除階段。一種可行的實現是,在標記階段首先通過根節點,標記所有從根節點開始的較大對象。因此,未被標記的對象就是未被引用的垃圾對象。然后,在清除階段,清除所有未被標記的對象。該算法最大的問題是存在大量的空間碎片,因為回收后的空間是不連續的。在對象的堆空間分配過程中,尤其是大對象的內存分配,不連續的內存空間的工作效率要低于連續的空間。

4. 標記-壓縮算法 (Mark-and-Compact)

復制算法的高效性是建立在存活對象少、垃圾對象多的前提下的。這種情況在年輕代經常發生,但是在老年代更常見的情況是大部分對象都是存活對象。如果依然使用復制算法,由于存活的對象較多,復制的成本也將很高。

標記-壓縮算法是一種老年代的回收算法,它在標記-清除算法的基礎上做了一些優化。也首先需要從根節點開始對所有可達對象做一次標記,但之后,它并不簡單地清理未標記的對象,而是將所有的存活對象壓縮到內存的一端。之后,清理邊界外所有的空間。這種方法既避免了碎片的產生,又不需要兩塊相同的內存空間,因此,其性價比比較高。

5. 分代 (Generational Collecting)

根據垃圾回收對象的特性,不同階段最優的方式是使用合適的算法用于本階段的垃圾回收,分代算法即是基于這種思想,它將內存區間根據對象的特點分成幾塊,根據每塊內存區間的特點,使用不同的回收算法,以提高垃圾回收的效率。

以 Hot Spot 虛擬機為例,它將所有的新建對象都放入稱為年輕代的內存區域,年輕代的特點是對象會很快回收,因此,在年輕代就選擇效率較高的復制算法。當一個對象經過幾次回收后依然存活,對象就會被放入稱為老生代的內存空間。在老生代中,幾乎所有的對象都是經過幾次垃圾回收后依然得以幸存的。因此,可以認為這些對象在一段時期內,甚至在應用程序的整個生命周期中,將是常駐內存的。如果依然使用復制算法回收老生代,將需要復制大量對象。再加上老生代的回收性價比也要低于新生代,因此這種做法也是不可取的。根據分代的思想,可以對老年代的回收使用與新生代不同的標記-壓縮算法,以提高垃圾回收效率。

6. 分類

-按線程數分,可以分為串行垃圾回收器和并行垃圾回收器。串行垃圾回收器一次只使用一個線程進行垃圾回收;并行垃圾回收器一次將開啟多個線程同時進行垃圾回收。在并行能力較強的 CPU 上,使用并行垃圾回收器可以縮短 GC 的停頓時間。

-按照工作模式分,可以分為并發式垃圾回收器和獨占式垃圾回收器。并發式垃圾回收器與應用程序線程交替工作,以盡可能減少應用程序的停頓時間;獨占式垃圾回收器 (Stop the world) 一旦運行,就停止應用程序中的其他所有線程,直到垃圾回收過程完全結束。

-按碎片處理方式可分為壓縮式垃圾回收器和非壓縮式垃圾回收器。壓縮式垃圾回收器會在回收完成后,對存活對象進行壓縮整理,消除回收后的碎片;非壓縮式的垃圾回收器不進行這步操作。

-按工作的內存區間,又可分為新生代垃圾回收器和老年代垃圾回收器。

7. 評估標準

-吞吐量:指在應用程序的生命周期內,應用程序所花費的時間和系統總運行時間的比值。系統總運行時間=應用程序耗時+GC 耗時。如果系統運行了 100min,GC 耗時 1min,那么系統的吞吐量就是 (100-1)/100=99%。

-垃圾回收器負載:和吞吐量相反,垃圾回收器負載指來記回收器耗時與系統運行總時間的比值。

-停頓時間:指垃圾回收器正在運行時,應用程序的暫停時間。對于獨占回收器而言,停頓時間可能會比較長。使用并發的回收器時,由于垃圾回收器和應用程序交替運行,程序的停頓時間會變短,但是,由于其效率很可能不如獨占垃圾回收器,故系統的吞吐量可能會較低。

-垃圾回收頻率:指垃圾回收器多長時間會運行一次。一般來說,對于固定的應用而言,垃圾回收器的頻率應該是越低越好。通常增大堆空間可以有效降低垃圾回收發生的頻率,但是可能會增加回收產生的停頓時間。

-反應時間:指當一個對象被稱為垃圾后多長時間內,它所占據的內存空間會被釋放。

-堆分配:不同的垃圾回收器對堆內存的分配方式可能是不同的。一個良好的垃圾收集器應該有一個合理的堆內存區間劃分。

參考:JVM 垃圾回收器工作原理及使用實例介紹

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容