日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

垃圾收集器ParNew&CMS與底層三色標記算法詳解

作者:bingtanghulu_6 更新時間: 2022-05-11 編程語言

目錄

1.垃圾收集算法

1.1 標記-復制算法

1.2 標記-清除算法

?1.3 標記-整理算法

?2.垃圾收集器

?2.1 Serial收集器

?2.2 Parallel Scavenge收集器

?2.3 ParallelNew收集器

?2.4 CMS收集器

3.電商系統(tǒng)優(yōu)化JVM參數(shù)設置

4. 三色標記原理


1.垃圾收集算法

常用的垃圾收集算法:分代收集理論(年輕代和老年代分別使用不同的垃圾回收算法),標記-復制算法(年輕代),標記整理算法(老年代),標記清除算法(老年代)。

1.1 標記-復制算法

?標記復制算法,會將內存分為兩塊,一半使用過的內存塊,一半未使用的內存塊,在進行垃圾收集時,將還存活的對象復制整理到未使用的內存塊,整理過后將使用過的內存塊清除。

主要在年輕代中使用這個算法。

缺點:浪費內存,每次1G的內存只能使用500M。

1.2 標記-清除算法

標記出所有存活的對象或者標記所有可回收的對象,標記-清除算法會產生兩個問題:

1. 效率問題:如果需要標記存活的對象太多會無法標記。

2. 空間問題:標記清理完成以后會產生大量的內存塊,如果需要一整塊連續(xù)的內存就會導致內存無法分配。

主要用于老年代中。

?

?1.3 標記-整理算法

通過標記垃圾對象將垃圾對象往存活對象一端移動,這樣最終生成的內存空間是一端連續(xù)的內存塊,存活對象和可使用對象。

?2.垃圾收集器

分代收集器:

????????年輕代:serial,ParNew,Parallel

????????老年代:CMS SerialOld Parallel Old

不分代算法:

? ? ? ? G1等,其他了解即可。

為什么要設計這么多垃圾收集器?就是因為內存在不斷變大,市面上沒有一種完美的垃圾收集器,都在不停完善中。垃圾收集算法是方法論,垃圾收集器是垃圾收集算法的具體實現(xiàn)。

tips:在大內存3-4G情況下推薦使用CMS收集器,如果只有2-3G使用Parallnel收集器,因為Parallnel收集器更關注吞吐量,STW只有一個過程集中用來垃圾回收,相對應STW時間會更短,但是CMS在大內存情況下犧牲了時間,為了用戶體驗至上,只有2個STW時間,最耗時間的并發(fā)標記不STW,用戶體驗上來說更好。

JDK8推薦CMS垃圾收集器,jdk9推薦使用G1垃圾收集器。jdk11推薦使用ZGC垃圾收集器。

JVM調優(yōu)例子,8G的內存分配4G給JVM,參數(shù)如下,按照順序 堆初始內存;堆最大內存 ;年輕代大小;桟線程大小;元空間初始值;元空間最大初始值 ;年輕代三個區(qū)域比例(Eden:S0:S1)=8:1:1 ;年輕代分代年齡(minor GC次數(shù));大對象

Xms3072M Xmx3072M Xmn2048M Xss1M XX : MetaspaceSize = 256 M XX : MaxMetaspaceSize = 256 M XX : SurvivorRatio = 8?
XX : MaxTenuringThreshold = 5 XX : PretenureSizeThreshold = 1 M

?2.1 Serial收集器

使用單線程實現(xiàn)垃圾回收,每次垃圾回收時都會停止所有工作線程專心做垃圾回收算法,也叫STW(Stop The World)。

優(yōu)點:簡單,適合于單核CPU中,幾十M的內存。

缺點:無法適用于現(xiàn)在多CPU電腦。效率低下。

年輕代和老年代都可以使用serial收集器:-XX:+UseSerialGC -XX:+UseSerialOldGC

新生代使用復制算法,老年代使用標記-整理算法。

?2.2 Parallel Scavenge收集器

并行垃圾收集器,跟serialn收集器不一樣的是在垃圾收集時使用多線程去垃圾回收。

年輕代和老年代都可以使用parallel收集器:-XX:+UseParallelGC?-XX:+UseParallelOldGC

還可以使用-XX:ParallelGCThreads指定線程收集垃圾,一般與計算機CPU核數(shù)相同。不建議修改。

新生代使用復制算法,老年代使用標記-整理算法。

jdk8默認使用這個垃圾收集器。

?2.3 ParallelNew收集器

ParallelNew收集器跟Parallel收集器基本相同,不同的一點是這個垃圾收集器可以兼容CMS收集器,年輕代使用ParallelNew收集器,老年代使用CMS收集器。

新生代使用復制算法,老年代使用標記-整理算法。

可以使用-XX:+UseParNewGC指定使用這個垃圾收集器。

?2.4 CMS收集器

CMS收集器(Concurrent Mark Sweep,并發(fā)標記清除)。

1.初始標記:暫停所有工作線程STW,然后標記Gc roots引用的直接對象。

? ? ? ? 直接對象:局部變量引用的new對象,靜態(tài)變量引用的new對象等。

? ? ? ? 這一步STW的目的是為了防止用戶線程產生大量的直接對象。

2.并發(fā)標記:使用多線程來垃圾回收,這一步不停止用戶線程,為了用戶體驗更好一些,初始標記很快,并發(fā)標記也不停止。可能導致對象狀態(tài)改變。

3.重新標記:主要為了修復并發(fā)標記過程中可能產生的對象狀態(tài)改變,主要使用了三色標記中的增量更新算法。這個過程也會STW,停頓時間大于初始標記,小于并發(fā)標記。

4.并發(fā)清理:開啟用戶線程,并發(fā)清理未被標記的區(qū)域,主要使用了三色標記算法。

5.并發(fā)重置:將三色標記的狀態(tài)還原,用于下一次垃圾回收標記。?

主要使用標記清除算法。

面試問題:并發(fā)清理中的浮動垃圾可以處理嗎?不可以,這次產生的浮動垃圾只能等待下一次Full GC才能回收。

標記清除的算法會導致大量空間碎片產生,可以通過開啟-XX:+UseCMSCompactAtFullCollection可以讓jvm在做完并發(fā)清理以后再做整理。

Concurrent Mode Fail:在并發(fā)標記過程有用戶線程有大量大對象產生,在FullGC時老年代無法清理出足夠的內存用來存儲大對象,此時會進入STW,CMS會切換為Serail OLD來清理老年代的內存,此時會變得很慢很慢。

CMS的相關核心參數(shù)
1. -XX:+UseConcMarkSweepGC:啟用cms
2. -XX:ConcGCThreads:并發(fā)的GC線程數(shù)
3. -XX:+UseCMSCompactAtFullCollection:FullGC之后做壓縮整理(減少碎片)
4. -XX:CMSFullGCsBeforeCompaction:多少次FullGC之后壓縮一次,默認是0,代表每次FullGC后都會壓縮一
5. -XX:CMSInitiatingOccupancyFraction: 當老年代使用達到該比例時會觸發(fā)FullGC(默認是92,這是百分比)
6. -XX:+UseCMSInitiatingOccupancyOnly:只使用設定的回收閾值(-XX:CMSInitiatingOccupancyFraction設
定的值),如果不指定,JVM僅在第一次使用設定值,后續(xù)則會自動調整
7. -XX:+CMSScavengeBeforeRemark:在CMS GC前啟動一次minor gc,目的在于減少老年代對年輕代的引
用,降低CMS GC的標記階段時的開銷,一般CMS的GC耗時 80%都在標記階段
8. -XX:+CMSParallellnitialMarkEnabled:表示在初始標記的時候多線程執(zhí)行,縮短STW
9. -XX:+CMSParallelRemarkEnabled:在重新標記的時候多線程執(zhí)行,縮短STW;

?

3.電商系統(tǒng)優(yōu)化JVM參數(shù)設置

電商系統(tǒng)如果JVM內存在4-6G使用ParNew(新生代)+CMS(老年代),如果大于8G推薦使用G1

ParNew+CMSJVM調優(yōu)例子,8G的內存分配4G給JVM,參數(shù)如下,按照順序 堆初始內存;堆最大內存 ;年輕代大小;桟線程大小;元空間初始值;元空間最大初始值 ;年輕代三個區(qū)域比例(Eden:S0:S1)=8:1:1 ;年輕代分代年齡(minor GC次數(shù));大對象;年輕代ParNew;老年代CMS;老年代92%的時候發(fā)生FullGC;標記整理后碎片整理;多少次FullGC以后發(fā)生碎片整理,默認0,一次FullGC就碎片整理,一般推薦配置個3也沒什么問題表示4次FullGC以后發(fā)生碎片整理

Xms3072M Xmx3072M Xmn2048M Xss1M XX : MetaspaceSize = 256 M XX : MaxMetaspaceSize = 256 M XX : SurvivorRatio = 8?
XX : MaxTenuringThreshold = 5 XX : PretenureSizeThreshold = 1 M
XX : + UseParNewGC XX : + UseConcMarkSweepGC
XX : CMSInitiatingOccupancyFraction = 92 XX : + UseCMSCompactAtFullCollection XX : CMSFullGCsBeforeCompaction = 0

4. 三色標記原理

三色標記:將對象的狀態(tài)分為白色,灰色,黑色。

從GC roots開始查找所有引用對象路徑,如果已經分析過的直接引用對象由白色改為黑色。

如果黑色引用的對象還有沒分析完的對象改為灰色

如果灰色引用的對象被標記過,沒有其他對象引用變?yōu)楹谏F渌麤]有被分析到的對象還是白色。

引用關系見下圖。

三色標記的問題:

漏標的解決方法:增量更新和STAB,

STAB很好理解,灰色對象回收白色對象時記錄下來,下一次標記的時候重新標記一次。下一次掃描結束以后以灰色為節(jié)點重新掃描一次,白色節(jié)點置為黑色。

增量更新:黑色插入白色標記時記錄下來,下一次標記時以黑色對象為跟把這個關系重新掃描一遍。相當于將黑色對象當作灰色對象。

寫屏障偽代碼實現(xiàn)

void update(int field,int newVlue){

? ? ? ? //寫前屏障

? ? ? ? field = newVlue;

? ? ? ? //寫后屏障

}

并發(fā)標記對漏標的解決方案:

CMS:使用寫屏障+增量更新實現(xiàn)

G1,shenandoah:使用寫屏障+STAB實現(xiàn)

ZGC:讀屏障

?

?

class A{
    private B b = new B();
}

class B{
    private C c = new C();
    private D d = new D();
}

class C{
}

class D{
}

原文鏈接:https://blog.csdn.net/qq_21575929/article/details/124330633

欄目分類
最近更新