溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

聊聊JAVA虛擬機(jī)中的垃圾收集器

發(fā)布時(shí)間:2020-08-05 17:04:51 來(lái)源:網(wǎng)絡(luò) 閱讀:2802 作者:lilugoodjob 欄目:軟件技術(shù)

前言

JAVA虛擬機(jī)的垃圾收集器是虛擬機(jī)內(nèi)存的清道夫,它的存在讓JAVA開(kāi)發(fā)人員能將更多精力投入到業(yè)務(wù)研發(fā)上。了解垃圾收集器,并利用好這個(gè)工具,能更好的保障服務(wù)穩(wěn)定性。這篇文章通過(guò)分析JAVA虛擬機(jī)內(nèi)存模型,介紹垃圾收集器常用算法和收集器類別,使得垃圾收集器的配置和使用變得不再遙不可及。

JAVA虛擬機(jī)內(nèi)存模型

JAVA虛擬機(jī)內(nèi)存可以劃分為:虛擬機(jī)棧、本地方法棧、JAVA堆內(nèi)存、方法區(qū)(包含運(yùn)行時(shí)常量池)、程序計(jì)數(shù)器、直接內(nèi)存。

虛擬機(jī)棧

虛擬機(jī)棧是線程私有的,生命周期跟線程相同。也就是說(shuō)一個(gè)線程被創(chuàng)建后,虛擬機(jī)為其分配了一個(gè)獨(dú)立的棧幀來(lái)存儲(chǔ)線程的局部變量、操作數(shù)、動(dòng)態(tài)鏈接、方法出口等信息,當(dāng)線程結(jié)束后,該棧幀也會(huì)被回收清理。

本地方法棧

本地方法棧是虛擬機(jī)的native方法執(zhí)行期間使用的一個(gè)棧幀。

JAVA堆內(nèi)存

堆內(nèi)存是被所有線程共享的一塊區(qū)域,用來(lái)存放對(duì)象實(shí)例和數(shù)組,屬于內(nèi)存中最大的一塊區(qū)域,也是垃圾收集的主要區(qū)域。從垃圾收集的角度看,堆內(nèi)存經(jīng)常分為新生代和老年代。

方法區(qū)

方法區(qū)也是被所有線程共享的一塊區(qū)域,用來(lái)存儲(chǔ)被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、JIT編譯后代碼等數(shù)據(jù)。也可以成為永久代。

程序計(jì)數(shù)器

程序計(jì)數(shù)器是線程私有的,作為當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器,每個(gè)線程有一個(gè)程序計(jì)數(shù)器,用于記錄CPU切換線程時(shí)記錄當(dāng)前線程的執(zhí)行位置,以便下次繼續(xù)從當(dāng)前位置往下執(zhí)行。

直接內(nèi)存

這塊不屬于JAVA虛擬機(jī)內(nèi)存,但使用頻繁,也可稱之為“堆外內(nèi)存”

JAVA虛擬機(jī)垃圾收集器

根據(jù)上述對(duì)JAVA虛擬機(jī)內(nèi)存區(qū)域模型的介紹,我們知道JAVA程序中的對(duì)象實(shí)例都存儲(chǔ)在JAVA堆內(nèi)存中,因此垃圾收集主要也是針對(duì)堆內(nèi)存進(jìn)行。為了更好的管理JAVA對(duì)象實(shí)例,并結(jié)合對(duì)象實(shí)例的生存時(shí)間長(zhǎng)短,JAVA虛擬機(jī)將堆內(nèi)存分為新生代和老年代,分別存儲(chǔ)剛創(chuàng)建不久的對(duì)象和存活較長(zhǎng)時(shí)間的對(duì)象實(shí)例,并采用分代收集的策略分別回收新生代和老年代的內(nèi)存。

內(nèi)存分配與回收策略
  • 1、 分代收集思路。根據(jù)JAVA對(duì)象的生存周期特點(diǎn),虛擬機(jī)將堆內(nèi)存分為新生代和老年代,并分別采用新生代和老年代的垃圾回收策略。
  • 2、 新生代細(xì)分為Eden區(qū)和兩個(gè)Survivor區(qū)(即From區(qū)和To區(qū))。大多數(shù)新生對(duì)象創(chuàng)建頻繁,且存活時(shí)間短,為了提高新生代區(qū)域垃圾收集效率,新創(chuàng)建的對(duì)象存放在Eden區(qū),當(dāng)Eden區(qū)快滿的時(shí)候,虛擬機(jī)對(duì)其觸發(fā)一次Minor GC,將新生代存活對(duì)象移動(dòng)到From區(qū),原來(lái)From區(qū)的對(duì)象根據(jù)存活年齡決定放到To區(qū)還是老年代,然后清空Eden區(qū)和From區(qū),接著將To區(qū)對(duì)象全部移到From區(qū)。
  • 3、 大對(duì)象直接進(jìn)入老年代,可以配置新生代對(duì)象的最大值,對(duì)象超過(guò)這個(gè)值就直接進(jìn)入老年代。
  • 4、 發(fā)起Minor GC前,會(huì)先判斷老年代最大可用連續(xù)空間是否大于新生代對(duì)象占用的空間,如果小于或不允許冒險(xiǎn),則觸發(fā)一次Full GC。
垃圾收集算法(3種基本算法)
  • 1、 復(fù)制算法。針對(duì)于新生代的垃圾收集算法。當(dāng)新生代Eden區(qū)快滿的時(shí)候,將Eden區(qū)對(duì)象復(fù)制到From區(qū),將From區(qū)對(duì)象根據(jù)存活年齡決定復(fù)制到To區(qū)還是到老年代,然后清除Eden區(qū)和From區(qū),接著將To區(qū)對(duì)象復(fù)制到From區(qū)。
  • 2、 標(biāo)記-清除算法。垃圾收集算法標(biāo)記出需要回收的對(duì)象,標(biāo)記完成后直接統(tǒng)一回收。垃圾收集器使用可達(dá)性分析來(lái)判斷哪些對(duì)象是否存活,通過(guò)設(shè)置一系列GC Roots節(jié)點(diǎn)(包括棧、方法區(qū)中的靜態(tài)屬性和常量所引用的對(duì)象,以及本地方法棧中引用的對(duì)象),從這類節(jié)點(diǎn)往下搜索,當(dāng)對(duì)象不在GC Root節(jié)點(diǎn)的引用鏈上時(shí),說(shuō)明對(duì)象不可達(dá),可以被回收。
  • 3、 標(biāo)記-整理算法。垃圾收集算法標(biāo)記出需要回收的對(duì)象,標(biāo)記完成后將存活對(duì)象往內(nèi)存的一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。
常用垃圾收集器

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

  • 1、 Serial GC。新生代收集器,采用復(fù)制算法,用于Client客戶端新生代垃圾收集,針對(duì)內(nèi)存占用較少的應(yīng)用進(jìn)行垃圾收集。
  • 2、 Serial Old GC。老年代收集器,采用標(biāo)記-整理算法,用于Client客戶端老年代垃圾收集,針對(duì)內(nèi)存占用較少的應(yīng)用進(jìn)行垃圾收集。
  • 3、 Parallel Scavenge GC。新生代收集器,采用復(fù)制算法,并行收集新生代內(nèi)存垃圾,可以設(shè)置垃圾收集器的吞吐量,還可以設(shè)置自動(dòng)適配調(diào)節(jié)吞吐量。
  • 4、 Parallel New GC。新生代收集器,采用復(fù)制算法,并行收集新生代內(nèi)存垃圾。
  • 5、 Parallel Old GC。老年代收集器,采用標(biāo)記-整理算法,并行收集老年代內(nèi)存垃圾。
  • 6、 CMS GC。老年代收集器,采用標(biāo)記-清除算法,并行收集老年代內(nèi)存垃圾,不整理內(nèi)存。由于在執(zhí)行垃圾收集期間不中斷業(yè)務(wù)線程,所以容易產(chǎn)出“浮動(dòng)垃圾”,導(dǎo)致Full GC。可以通過(guò)設(shè)置參數(shù)來(lái)觸發(fā)內(nèi)存整理任務(wù)。
  • 7、 G1 GC。不再將堆內(nèi)存區(qū)分新生代和老年代,而是將堆內(nèi)存看作若干個(gè)均分小區(qū)域,并對(duì)最空閑的內(nèi)存區(qū)域進(jìn)行標(biāo)記和回收。適用于大內(nèi)存的應(yīng)用。
配置垃圾收集機(jī)器參數(shù)
  • 1、UseSerialGC:虛擬機(jī)允許在Client模式下的默認(rèn)值,打開(kāi)此配置后,虛擬機(jī)使用Serial GC + Serial Old GC 的收集器組合進(jìn)行內(nèi)存回收。
  • 2、UseParNewGc:使用ParNew + Serial Old 的收集器組合進(jìn)行內(nèi)存回收。
  • 3、UseConcMarkSweepGC:使用ParNew + CMS + Serial Old GC的收集器組合進(jìn)行內(nèi)存回收。
  • 4、UseParallelGC:虛擬機(jī)允許在Server模式下的默認(rèn)值,使用Parallel Scavenge + Serial Old 的收集器組合進(jìn)行內(nèi)存回收。
  • 5、UseParallelOldGC: 使用Parallel Scavenge + Parallel Old GC的收集器組合進(jìn)行內(nèi)存回收。
  • 6、SuriviorRatio:新生代中Eden區(qū)域與Surivior區(qū)域的容量比值,默認(rèn)是8:1。
  • 7、PretenureSizeThreshold:設(shè)置這個(gè)值后,大于這個(gè)值的對(duì)象直接進(jìn)入老年代。
  • 8、MaxtenuringThreshold:對(duì)象年齡超過(guò)這個(gè)值時(shí)進(jìn)入老年代。
  • 9、ParallelGCThreads:設(shè)置并行GC時(shí)進(jìn)行內(nèi)存回收的線程數(shù)。
  • 10、UseAdaptiveSizePolicy:動(dòng)態(tài)調(diào)整堆內(nèi)存中各個(gè)區(qū)域的大小和進(jìn)入老年代的對(duì)象年齡。
  • 11、HandlerPromotionFailure:是否允許分配擔(dān)保失敗。
  • 12、GCTimeRatio:僅在Parallel ScaVenge收集器時(shí)生效,設(shè)置GC時(shí)間占總運(yùn)行時(shí)間的比率,默認(rèn)為1%。
  • 13、MaxGCPauseMills:僅在Parallel ScaVenge收集器時(shí)生效,設(shè)置GC的最大停頓時(shí)間。
  • 14、CMSInitiatingOccupancyFraction:設(shè)置CMS收集器在老年代空間被使用多少后觸發(fā)垃圾收集,默認(rèn)68%,在設(shè)置CMS收集器時(shí)生效。
  • 15、UseCMSCompactAtFullCollection:在設(shè)置CMS收集器時(shí)生效,設(shè)置CMS收集器在完成垃圾收集后是否進(jìn)行一次碎片整理。
  • 16、CMSFullGCsBeforeCompaction:僅在使用CMS時(shí)生效,設(shè)置CMS收集器在進(jìn)行若干次收集后再啟動(dòng)一次內(nèi)存碎片整理。
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI