Java虛擬機四:垃圾回收算法與垃圾收集器

Java虛擬機四:垃圾回收算法與垃圾收集器
在Java運行時的幾個數據區域中,程序計數器,虛擬機棧,本地方法棧3個區域隨着線程而生,隨線程而滅,因此這幾個區域的內存分配和回收具有確定性,不需要過多考慮垃圾回收問題,因爲方法結束或者線程結束時,內存就回收了。但是方法區和堆區不一樣,一個接口或者實現類所需要的內存可能不一樣,一個方法的多個分支需要的內存也可能不一樣,只有程序運行時才能知道創建哪些對象,這部分內存的分配和回收是動態的。

  在進行垃圾回收時候,首先需要判斷哪些對象需要回收,這就涉及到回收算法的問題。

一、垃圾回收算法

1.標記-清除算法

  標記-清除算法是一種最基礎的垃圾收集算法,分爲“標記”和“清除”兩步。“標記”階段標記所有需要進行垃圾回收的對象,標記完成後統一回收被標記的對象。這種算法的不足點在於:

  (1)效率問題,標記和清除兩個過程效率都不高;

  (2)空間問題,標記清除後會產生大量不連續碎片,後續如果需要爲較大對象分配空間,則又需觸發垃圾回收。

2.複製算法

  爲了解決標記-清除算法的效率問題,出現了複製算法。這種算法把內存按照容量劃分爲大小相同的兩塊,每次只是用其中一塊,當這塊內存用完了,就把還存活的對象複製到另外一塊中,並將這塊的內存清理掉,然後使用另外一塊,當另外一塊內存用完了,再把存活的對象複製到這塊中,並清理另外一塊內存,依次類推。

  複製算法主要用於新生代的回收,在HotSpot虛擬機中,新生代內存劃分爲一塊較大的Eden空間,和兩塊較小的Survivor空間,每次使用Eden空間和其中一塊Survivor空間。當進行垃圾回收時,會把Eden空間和Survivor空間中存活的對象一次性複製到另外一塊Survivor空間上,最後清理掉Eden空間和剛纔使用過的Survivor空間。HotSpot虛擬機中,默認情況下Eden空間和Survivor空間的大小比例是8:1,即Eden空間佔整個新生代的80%,每次新生代中使用的空間爲80%+10%=90%,閒置空間10%。

3.標記-整理算法

  複製算法適用於那種對象存活率較低的場景,在對象存活率較高時,使用複製收集算法意味着需要進行大量複製,會使效率降低,同時複製大量存活對象到另外一塊內存,意味着需要有足夠大的內存來保存這些對象,這勢必會降低內存使用率。根據老年代的特點,有人提出標記-整理算法,和標記-清除算法不同的是,標記整理算法將存活的對象向一端移動,然後直接清理掉端邊界之外的內存。

4.分代收集算法

  目前商業虛擬機中都使用分代收集算法。一般將Java堆分爲新生代和老年代,新生代進行垃圾收集發現有大量對象死去,只有少量對象存活,那麼就使用複製算法。老年代中對象存活率較高,使用標記-清除算法或者標記-整理算法。

二、垃圾收集器

  垃圾收集算法提供了內存回收的方法論,垃圾收集器是內存回收的方法論。每個廠商對垃圾收集器的實現不一樣,這裏主要討論Jdk1.7 Update 14之後的HotSpot虛擬機。這個虛擬機中包含的垃圾收集器有如下7種:

    以上收集器之間如果有連線,則表明可以搭配使用,虛擬機所處區域,表示他是新生代收集器還是老年代收集器。

1.Serial收集器

  Serial收集器是一種最基本的單線程收集器,這種收集器工作時,必須停止其他所有工作線程,優點在於簡單高效,但體驗很不友好,目前主要應用場合是:虛擬機運行在Client模式下的默認新生代收集。器。

2.ParNew收集器

  parNew收集器是Serial收集器的多線程版本,常用參數設置:

   -XX:+UseConcMarkSweepGC :設置ParNew爲默認的新生代收集器;

   -XX:+UseParNewGC :指定使用ParNew爲年輕代收集器,強制指定;

   -XX:ParallelGCThreads=n :設置收集器的線程數爲n。

3.Parallel Scavenge收集器

  Parallel Scavenge收集器是一個使用複製算法的新生代收集器,這種收集器的主要目標是達到一個可控制的吞吐量(Throughput,CPU用於運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間))。由於與吞吐量關係密切,故而Parallel Scavenge收集器也稱爲“吞吐量優先”收集器。常用參數設置:

   -XX:MaxGCPauseMillis=n :設置年輕代垃圾收集的最長時間;

   -XX:GCTimeRatio=n :設置垃圾收集總可用時長的比例,和吞吐量直接相關;

   -XX:+UseAdaptiveSizePolicy 自適應大小開關,配置該選項之後,每次GC後會重新計算 Eden、From 和 To 區的大小,計算依據是 GC 過程中統計的 GC 時間、吞吐量、內存佔用量,因此設置此參數之後就不需要再設置 -XX:SurvivorRatio 、 -XX:PretenureSizeThreshold 等參數了。

4.Serial Old收集器

  Serial收集器的老年版本,也是一個單線程收集器,使用的是“標記-整理”算法,這種收集器的主要意義也是給Client模式下的虛擬機使用。

5.Parallel Old收集器

  Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”算法。在注重吞吐量以及CPU資源敏感的場合,都可以優先考慮Parallel Scavenge收集器和Parallel Old收集器的組合。

6.CMS收集器

  CMS收集器是一種以獲取最短回收停頓時間爲目標的收集器。它基於“標記-清除”算法實現,運作過程相對於其他幾種收集器更復雜一些。分爲以下四個過程:

  (1)初始標記(CMS initial mark):標記一下CG Roots能關聯到的對象;

  (2)併發標記(CMS concurrent mark):進行CG Roots Tracing的過程;

  (3)重新標記(CMS remark):修正併發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄。

  (4)併發清理(CMS concurrent sweep)

  CMS 收集器的優點在於併發收集,低停頓。其缺點在於以下三點:

  (1)CMS收集器對CPU很敏感,CMS默認回收線程是(CPU數量+3)/4,當CPU在4個以上時,併發收集時垃圾收集線程不少於25%的CPU資源,並隨着CPU數量增加而下降。但是當CPU不足4個時,CMS對用戶程序的影響就會變得很大。

  (2)CMS收集器無法處理浮動垃圾。由於CMS收集器併發清理階段用戶線程還在運行着,伴隨着程序運行就會有垃圾產生,這部分垃圾在標記過後,CMS收集器無法在當次收集中清理這些垃圾。

  (3)由於CMS收集器是一種基於“標記-清除”算法的收集器,這種算法實現的收集器在收集結束後會有大量不連續碎片產生。碎片過多時會給大對象分配帶來很大麻煩,往往老年代還有很大空間剩餘,但是無法找到連續空間分配當前對象,因而不得不提前觸發Full GC。

7.G1收集器

  G1收集器是一款面向服務端應用的垃圾收集器,與其他收集器相比,G1收集器具有如下優點:

  (1)併發與並行:G1能充分利用多CPU,多核硬件優勢,使用多個CPU來減少停頓時間;

  (2)分代收集:G1不需要其他收集器配合就能獨立管理整個堆的垃圾收集,且它能採用不同方式去處理新建對象和已經存活了一段時間,熬過多次GC的舊對象以獲得更好的收集效果。

  (3)空間整合:使用G1收集器不會產生內存碎片,收集後能提供規整的可用內存。這種特性有利於程序長時間運行,分配大對象時候不會因爲無法找到連續內存空間而提前觸發下一次GC.

  (4)可預測的停頓:G1除了追求低停頓,還能建立可預測的停頓時間模型,能讓使用着指定在長度爲M毫秒的時間片段內,消耗在垃圾收集上的時間不超過N毫秒。

三、垃圾收集參數總結

參數 描述
UseSerialGC
虛擬機運行在Client模式下的默認值,打開此開關後,使用Serial+Serial Old的收集器組合進行內存回收

UseParNewGC 打開此開關後,使用ParNew + Serial Old 的收集器組合進行內存回收
UseConcMarkSweepGC 打開此開關後,使用ParNew + CMS + Serial Old 的收集器組合進行內存回收。Serial Old 收集器將作爲CMS收集器出現Concurrent Mode Failure失敗後的後備收集器使用
UseParallelGC 虛擬機運行在Server 模式下的默認值,打開此開關後,使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器組合進行內存回收
UseParallelOldGC 打開此開關後,使用Parallel Scavenge + Parallel Old 的收集器組合進行內存回收
SurvivorRatio 新生代中Eden 區域與Survivor 區域的容量比值,默認爲8,代表Eden :Survivor=8∶1
PretenureSizeThreshold 直接晉升到老年代的對象大小,設置這個參數後,大於這個參數的對象將直接在老年代分配
MaxTenuringThreshold 晉升到老年代的對象年齡。每個對象在堅持過一次Minor GC 之後,年齡就加1,當超過這個參數值時就進入老年代
UseAdaptiveSizePolicy 動態調整Java 堆中各個區域的大小以及進入老年代的年齡
HandlePromotionFailure 是否允許分配擔保失敗,即老年代的剩餘空間不足以應付新生代的整個Eden 和Survivor 區的所有對象都存活的極端情況
ParallelGCThreads 設置並行GC 時進行內存回收的線程數
GCTimeRatio GC 時間佔總時間的比率,默認值爲99,即允許1% 的GC 時間。僅在使用Parallel Scavenge 收集器時生效
MaxGCPauseMillis 設置GC 的最大停頓時間。僅在使用Parallel Scavenge 收集器時生效
CMSInitiatingOccupancyFraction 設置CMS 收集器在老年代空間被使用多少後觸發垃圾收集。默認值爲68%,僅在使用CMS 收集器時生效
UseCMSCompactAtFullCollection 設置CMS 收集器在完成垃圾收集後是否要進行一次內存碎片整理。僅在使用CMS 收集器時生效
CMSFullGCsBeforeCompaction 設置CMS 收集器在進行若干次垃圾收集後再啓動一次內存碎片整理,僅在使用CMS 收集器時生效
原文地址https://www.cnblogs.com/fengweiweicoder/p/10787454.html

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