聊聊JAVA虛擬機中的垃圾收集器

前言

JAVA虛擬機的垃圾收集器是虛擬機內存的清道夫,它的存在讓JAVA開發人員能將更多精力投入到業務研發上。瞭解垃圾收集器,並利用好這個工具,能更好的保障服務穩定性。這篇文章通過分析JAVA虛擬機內存模型,介紹垃圾收集器常用算法和收集器類別,使得垃圾收集器的配置和使用變得不再遙不可及。

JAVA虛擬機內存模型

JAVA虛擬機內存可以劃分爲:虛擬機棧、本地方法棧、JAVA堆內存、方法區(包含運行時常量池)、程序計數器、直接內存。

虛擬機棧

虛擬機棧是線程私有的,生命週期跟線程相同。也就是說一個線程被創建後,虛擬機爲其分配了一個獨立的棧幀來存儲線程的局部變量、操作數、動態鏈接、方法出口等信息,當線程結束後,該棧幀也會被回收清理。

本地方法棧

本地方法棧是虛擬機的native方法執行期間使用的一個棧幀。

JAVA堆內存

堆內存是被所有線程共享的一塊區域,用來存放對象實例和數組,屬於內存中最大的一塊區域,也是垃圾收集的主要區域。從垃圾收集的角度看,堆內存經常分爲新生代和老年代。

方法區

方法區也是被所有線程共享的一塊區域,用來存儲被虛擬機加載的類信息、常量、靜態變量、JIT編譯後代碼等數據。也可以成爲永久代。

程序計數器

程序計數器是線程私有的,作爲當前線程所執行的字節碼的行號指示器,每個線程有一個程序計數器,用於記錄CPU切換線程時記錄當前線程的執行位置,以便下次繼續從當前位置往下執行。

直接內存

這塊不屬於JAVA虛擬機內存,但使用頻繁,也可稱之爲“堆外內存”

JAVA虛擬機垃圾收集器

根據上述對JAVA虛擬機內存區域模型的介紹,我們知道JAVA程序中的對象實例都存儲在JAVA堆內存中,因此垃圾收集主要也是針對堆內存進行。爲了更好的管理JAVA對象實例,並結合對象實例的生存時間長短,JAVA虛擬機將堆內存分爲新生代和老年代,分別存儲剛創建不久的對象和存活較長時間的對象實例,並採用分代收集的策略分別回收新生代和老年代的內存。

內存分配與回收策略

  • 1、 分代收集思路。根據JAVA對象的生存週期特點,虛擬機將堆內存分爲新生代和老年代,並分別採用新生代和老年代的垃圾回收策略。
  • 2、 新生代細分爲Eden區和兩個Survivor區(即From區和To區)。大多數新生對象創建頻繁,且存活時間短,爲了提高新生代區域垃圾收集效率,新創建的對象存放在Eden區,當Eden區快滿的時候,虛擬機對其觸發一次Minor GC,將新生代存活對象移動到From區,原來From區的對象根據存活年齡決定放到To區還是老年代,然後清空Eden區和From區,接着將To區對象全部移到From區。
  • 3、 大對象直接進入老年代,可以配置新生代對象的最大值,對象超過這個值就直接進入老年代。
  • 4、 發起Minor GC前,會先判斷老年代最大可用連續空間是否大於新生代對象佔用的空間,如果小於或不允許冒險,則觸發一次Full GC。

垃圾收集算法(3種基本算法)

  • 1、 複製算法。針對於新生代的垃圾收集算法。當新生代Eden區快滿的時候,將Eden區對象複製到From區,將From區對象根據存活年齡決定複製到To區還是到老年代,然後清除Eden區和From區,接着將To區對象複製到From區。
  • 2、 標記-清除算法。垃圾收集算法標記出需要回收的對象,標記完成後直接統一回收。垃圾收集器使用可達性分析來判斷哪些對象是否存活,通過設置一系列GC Roots節點(包括棧、方法區中的靜態屬性和常量所引用的對象,以及本地方法棧中引用的對象),從這類節點往下搜索,當對象不在GC Root節點的引用鏈上時,說明對象不可達,可以被回收。
  • 3、 標記-整理算法。垃圾收集算法標記出需要回收的對象,標記完成後將存活對象往內存的一端移動,然後直接清理掉端邊界以外的內存。

常用垃圾收集器

由於虛擬機中的垃圾收集是分代收集的,新生代和老年代的垃圾收集策略不太一樣,所以一般是使用針對新生代和老年代的垃圾收集器組合。

  • 1、 Serial GC。新生代收集器,採用複製算法,用於Client客戶端新生代垃圾收集,針對內存佔用較少的應用進行垃圾收集。
  • 2、 Serial Old GC。老年代收集器,採用標記-整理算法,用於Client客戶端老年代垃圾收集,針對內存佔用較少的應用進行垃圾收集。
  • 3、 Parallel Scavenge GC。新生代收集器,採用複製算法,並行收集新生代內存垃圾,可以設置垃圾收集器的吞吐量,還可以設置自動適配調節吞吐量。
  • 4、 Parallel New GC。新生代收集器,採用複製算法,並行收集新生代內存垃圾。
  • 5、 Parallel Old GC。老年代收集器,採用標記-整理算法,並行收集老年代內存垃圾。
  • 6、 CMS GC。老年代收集器,採用標記-清除算法,並行收集老年代內存垃圾,不整理內存。由於在執行垃圾收集期間不中斷業務線程,所以容易產出“浮動垃圾”,導致Full GC。可以通過設置參數來觸發內存整理任務。
  • 7、 G1 GC。不再將堆內存區分新生代和老年代,而是將堆內存看作若干個均分小區域,並對最空閒的內存區域進行標記和回收。適用於大內存的應用。

配置垃圾收集機器參數

  • 1、UseSerialGC:虛擬機允許在Client模式下的默認值,打開此配置後,虛擬機使用Serial GC + Serial Old GC 的收集器組合進行內存回收。
  • 2、UseParNewGc:使用ParNew + Serial Old 的收集器組合進行內存回收。
  • 3、UseConcMarkSweepGC:使用ParNew + CMS + Serial Old GC的收集器組合進行內存回收。
  • 4、UseParallelGC:虛擬機允許在Server模式下的默認值,使用Parallel Scavenge + Serial Old 的收集器組合進行內存回收。
  • 5、UseParallelOldGC: 使用Parallel Scavenge + Parallel Old GC的收集器組合進行內存回收。
  • 6、SuriviorRatio:新生代中Eden區域與Surivior區域的容量比值,默認是8:1。
  • 7、PretenureSizeThreshold:設置這個值後,大於這個值的對象直接進入老年代。
  • 8、MaxtenuringThreshold:對象年齡超過這個值時進入老年代。
  • 9、ParallelGCThreads:設置並行GC時進行內存回收的線程數。
  • 10、UseAdaptiveSizePolicy:動態調整堆內存中各個區域的大小和進入老年代的對象年齡。
  • 11、HandlerPromotionFailure:是否允許分配擔保失敗。
  • 12、GCTimeRatio:僅在Parallel ScaVenge收集器時生效,設置GC時間佔總運行時間的比率,默認爲1%。
  • 13、MaxGCPauseMills:僅在Parallel ScaVenge收集器時生效,設置GC的最大停頓時間。
  • 14、CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少後觸發垃圾收集,默認68%,在設置CMS收集器時生效。
  • 15、UseCMSCompactAtFullCollection:在設置CMS收集器時生效,設置CMS收集器在完成垃圾收集後是否進行一次碎片整理。
  • 16、CMSFullGCsBeforeCompaction:僅在使用CMS時生效,設置CMS收集器在進行若干次收集後再啓動一次內存碎片整理。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章