《深入理解Java虛擬機》讀後總結 (四)JVM垃圾回收

(一)JVM內存模型
(二)JVM內存分配
(三)JVM內存監控
(四)JVM垃圾回收

JVM的GC概述

GC即垃圾回收,是指jvm用於釋放那些不再使用的對象所佔用的內存。
在充分理解了垃圾收集算法和執行過程後,纔能有效的優化它的性能。
有些垃圾收集專用於特殊的應用程序。比如,實時應用程序主要是爲了避免垃圾收集中斷,而大多數OLTP應用程序則注重整體效率。
垃圾收集的目的在於清除不再使用的對象。gc通過確定對象是否被活動對象引用來確定是否收集該對象。兩種常用的方法是引用計數和對象引用遍歷。
引用計數
引用計數存儲對特定對象的所有引用數,也就是說,當應用程序創建引用以及引用超出範圍時,jvm必須適當增減引用數。當某對象的引用數爲0時,便可以進行垃圾收集。
對象引用遍歷
早期的jvm使用引用計數,現在大多數jvm採用對象引用遍歷。對象引用遍歷從一組對象開始,沿着整個對象圖上的每條鏈接,遞歸確定可到達(reachable)的對象。如果某對象不能從這些根對象的一個(至少一個)到達,則將它作爲垃圾收集。在對象遍歷階段,gc必須記住哪些對象可以到達,以便刪除不可到達的對象,這稱爲標記(marking)對象。

基本的回收算法:

空間維度:標記-清除、標記-壓縮、標記-複製、增量回收、分代回收
時間維度:串行回收、併發回收、並行回收

標記-清除:

標記清除的算法最簡單,主要是標記出來需要回收的對象,然後然後把這些對象在內存的信息清除,會產生大量內存碎片。
這裏寫圖片描述

標記-壓縮

有時也叫標記-清除-壓縮收集器,這個算法是在標記-清除的算法之上進行剪切操作,將存活對象壓縮在一起,減少內存碎片。由於壓縮空間需要一定的時間,會影響垃圾收集的時間。
這裏寫圖片描述

標記-複製

這個算法是把內存分配爲兩個空間,一個空間(A)用來負責裝載正常的對象信息,另外一個內存空間(B)是垃圾回收用的。
每次把空間A中存活的對象全部複製到空間B裏面,在一次性的把空間A刪除。
這個算法在效率上比標記-清除-壓縮高,但是需要兩塊空間,對內存要求比較大,內存的利用率比較低。適用於短生存期的對象,持續複製長生存期的對象則導致效率降低。
這裏寫圖片描述

增量回收:

增量回收器:把堆分爲多個域,每次對從一個域進行垃圾回收。這樣只會早點一小部分程序暫停。
分代回收:
基於對對象生命週期分析後得出的垃圾回收算法。把對象分爲年青代、年老代、持久代,對不同生命週期的對象使用不同的算法進行回收。

串行回收:

用單線程處理所有垃圾回收工作,因爲無需多線程交互,所以效率比較高。但是,也無法使用多處理器的優勢,所以此收集器適合單處理器機器
這裏寫圖片描述

並行回收:

用多線程處理所有垃圾回收工作,利用多核處理器的優勢。對於空間不大的區域(如young generation),採用並行收集器停頓時間很短,回收效率高,適合高頻率執行。但是如果線程數量過多,導致線程之間頻繁調度,也會影響性能。一般並行收集的線程數是處理器的個數。
這裏寫圖片描述

併發回收:

併發收集器GC時GC線程和應用線程大部分時間是併發執行,只是在初始標記(initial mark)和二次標記(remark)時需要stop-the-world,這可以大大縮短停頓時間(pause time),所以適用於響應時間優先的應用,減少用戶等待時間。由於GC是和應用線程併發執行,只有在多CPU場景下才能發揮其價值,在一個N個處理器的系統上,併發收集部分使用K/N個可用處理器進行回收,一般情況下1<=K<=N/4。 在執行過程中還會產生新的垃圾floating garbage(浮動垃圾),如果等空間滿了再開始GC,那這些新產生的垃圾就沒地方放了(併發收集器一般需要20%的預留空間用於這些浮動垃圾),這時就會啓動一次串行GC,等待時間將會很長,所以要在空間還未滿時就要啓動GC。mark和sweep操作會引起很多碎片,所以間隔一段時間需要整理整個空間,否則遇到大對象,沒有連續空間也會啓動一次串行GC。採用此收集器,收集頻率不能大,否則會影響到cpu的利用率,進而影響吞吐量。
這裏寫圖片描述

JVM的GC觸發原理

JVM的GC主要是對堆內存的回收,
一般把新生代的GC稱爲minor GC ,把老年代的GC成爲 full GC,所謂full gc會先出發一次minor gc,然後在進行老年代的GC。
首先想eden區申請分配空間,如果空間夠,就直接進行分配,否則進行一次Minor GC。
minor GC 首先會對Eden區的對象進行標記,標記出來存活的對象。然後把存活的對象copy到From空間。
如果From空間足夠,則回收eden區可回收的對象。
如果from內存空間不夠,則把From空間存活的對象複製到To區,
如果TO區的內存空間也不夠的話,則把To區存活的對象複製到老年代。
如果老年代空間也不夠(或者達到觸發老年年垃圾回收條件的話)則觸發一次full GC。
簡單方向就是Eden->From->To->Old,如下圖所示:
這裏寫圖片描述

默認是不會對持久帶(方法區)進行垃圾回收的,設置參數可回收:-XX:+CMSClassUnloadingEnabled

JVM支持的GC收集器
JVM採用的是分代回收,不同代有不同的垃圾收集器
如圖所示:連線的是可以組合使用
這裏寫圖片描述

各個收集器的細節我就不在這裏COPY/PASTE了,SerialOld收集器在書的圖中沒有,是我後加上的,其實很少使用。
感興趣的可以試讀,試讀地址http://book.51cto.com/art/201107/278857.htm,有前三章的內容。

發佈了63 篇原創文章 · 獲贊 134 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章