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

《深入理解Java虛擬機》讀後總結

(一)Sun HotSpot JVM內存模型

(二)Sun HotSpot JVM內存分配

(三)Sun HotSpot JVM內存監控

(四)Sun HotSpot 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,有前三章的內容。

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