1.JVM內(nèi)存空間
JVM堆(Heap)= 新生代(Young) + 舊生代(Tenured)
分區(qū)作用:
新創(chuàng)建的對(duì)象通常先將其分配在新生代中,,在新生代中經(jīng)過若干次GC之后仍未釋放的對(duì)象,,再將它移動(dòng)到舊生代,。為了讓內(nèi)存回收更高效(GC會(huì)暫停JVM中的應(yīng)用),Sun JDK在1.2開始對(duì)堆采用了分代管理的方式,。在分配對(duì)象遇到內(nèi)存不足時(shí),,先對(duì)新生代進(jìn)行GC(Young GC);當(dāng)新生代GC之后仍無法滿足內(nèi)存空間分配需求時(shí),, 才會(huì)對(duì)整個(gè)堆空間以及方法區(qū)進(jìn)行GC (Full GC)
相關(guān)參數(shù):
-Xms -- 設(shè)置堆內(nèi)存初始大小
-Xmx -- 設(shè)置堆內(nèi)存最大值
-XX:MaxTenuringThreshold -- 設(shè)置對(duì)象在新生代中存活的次數(shù)
-XX:PretenureSizeThreshold -- 設(shè)置超過指定大小的大對(duì)象直接分配在舊生代中
注意點(diǎn):當(dāng)新生代設(shè)置得太小時(shí),,也可能引發(fā)大對(duì)象直接分配到舊生代中。
新生代(Young)= Eden區(qū) + Survivor區(qū)
分區(qū)作用:
Eden區(qū)為對(duì)象通常最初分配到的地方,,Survivor區(qū)分為S0和S1兩塊大小相等的區(qū)域,。JVM進(jìn)行Minor GC時(shí),將Eden中還存活的對(duì)象拷貝到Survivor區(qū)中,,還會(huì)將Survivor區(qū)中還存活的對(duì)象拷貝到Tenured區(qū)中,。在這種GC模式下,JVM為了提升GC效率,, 將Survivor區(qū)分為S0和S1,,這樣就可以將對(duì)象回收和對(duì)象晉升分離開來。
相關(guān)參數(shù):
-Xmn -- 設(shè)置新生代內(nèi)存大小,。
-XX:SurvivorRatio -- 設(shè)置Eden與Survivor空間的大小比例
注意點(diǎn): 圖中Virtual部分表示可伸縮的內(nèi)存空間,,當(dāng)用-Xms在指定堆的初始大小為128m,通過-Xmx指定堆最大為256m時(shí),,JVM會(huì)根據(jù)內(nèi)存情況在128m與256m之間伸縮,。為了避免JVM進(jìn)行這些伸縮消耗性能,對(duì)于能夠提供穩(wěn)定內(nèi)存空間的用作服務(wù)器的JVM,,通常將-Xms和-Xmx設(shè)置為相等,。
方法區(qū)(Perm)
分區(qū)作用:
也被成為持久代,用來存放JVM加載的類型信息,。包括: 類型基本信息,,常量池,字段信息,,方法信息,,類變量,指向ClassLoader的引用,,Class類的引用,,方法表等。方法區(qū)是全局共享的,,在一定條件下也會(huì)被GC,。
相關(guān)參數(shù):
-XX:PermSize --設(shè)置Perm區(qū)的初始大小
-XX:MaxPermSize --設(shè)置Perm區(qū)的最大值
JVM方法棧(注意:不是分區(qū))
作用:
JVM方法棧為JVM線程私有內(nèi)存,當(dāng)方法運(yùn)行完畢后,,其對(duì)應(yīng)的棧幀內(nèi)存會(huì)自動(dòng)釋放
相關(guān)參數(shù):
-Xss --設(shè)置方法棧的最大值
TLAB:
JVM所占用的主要內(nèi)存都是從堆空間分配的,,堆是所有線程共享的,,因此在堆上分配內(nèi)存需要加鎖,Sun JDK為提升效率,,會(huì)為每個(gè)新建的線程在Eden上分配一塊獨(dú)立的空間由該線程獨(dú)享,,這塊空間稱為TLAB(Thread Local Allocation Buffer)。其大小由JVM根據(jù)運(yùn)行情況計(jì)算得到,,也可通過參數(shù)-XX:TLABWasteTargetPercent來設(shè)置TLAB可占用的Eden空間的百分比,,默認(rèn)值為1%。在TLAB上分配內(nèi)存不需要加鎖,,因此JVM在給線程中的對(duì)象分配內(nèi)存時(shí)會(huì)盡量在TLAB上分配,。如果對(duì)象過大或TLAB用完,則仍然在堆上進(jìn)行分配,。
2.Sun JDK GC收集器
收集器主要分為引用計(jì)數(shù)器和跟蹤收集器兩種,,Sun JDK中采用跟蹤收集器作為GC實(shí)現(xiàn)策略。
跟蹤收集器簡(jiǎn)介
跟蹤收集器采用集中式的管理方式,,全局記錄數(shù)據(jù)的引用狀態(tài),。觸發(fā)執(zhí)行時(shí)需要從根節(jié)點(diǎn)來掃描對(duì)象的引用關(guān)系,可能會(huì)造成應(yīng)用程序暫停,。主要有三種實(shí)現(xiàn)算法:復(fù)制(Copying) ,、 標(biāo)記-清除(Mark-Sweep) 、 標(biāo)記-壓縮(Mark-Compact) ,。下文將簡(jiǎn)單介紹這三種算法的過程,,有助于后續(xù)的GC策略理解和分析。
復(fù)制(Copying)
算法:復(fù)制采用的方式為從根集合掃描出存活的對(duì)象,,并將找到的存活對(duì)象復(fù)制到一塊新的完全未使用的空間中,。
過程:注意,紅叉為不存活的對(duì)象所占用內(nèi)存空間
標(biāo)記-清除(Mark-Sweep)
算法:標(biāo)記-清除采用的方式為從根集合開始掃描,,對(duì)存活的對(duì)象進(jìn)行標(biāo)記,,標(biāo)記完畢后,,再掃描整個(gè)空間中未標(biāo)記的對(duì)象,,并進(jìn)行回收。
過程:
ü 優(yōu)缺點(diǎn):在空間中存活對(duì)象較多的情況下較為高效,,但由于該算法為直接回收不存活對(duì)象所占用的內(nèi)存,,因此會(huì)造成內(nèi)存碎片。
標(biāo)記-壓縮(Mark-Compact)
ü 算法:標(biāo)記階段與“標(biāo)記-清除”算法相同,,但在清除階段有所不同,。在回收不存活對(duì)象所占用的內(nèi)存空間后,會(huì)將其他所有存活對(duì)象都往左端空閑的空間進(jìn)行移動(dòng),,并更新引用其對(duì)象指針,。
ü 過程:
ü 優(yōu)缺點(diǎn):在“標(biāo)記-清除”的基礎(chǔ)上還需要進(jìn)行對(duì)象移動(dòng),,成本相對(duì)較高,好處則是不產(chǎn)生內(nèi)存碎片,。
3. Sun JDK GC策略
圖4 Sun JDK中可用的GC方式
基于上一小節(jié)講解的跟蹤收集器算法,,Sun JDK在新生代和老生代進(jìn)行了不同的算法實(shí)現(xiàn),形成了上圖中的GC方式分布,。本小節(jié)將具體介紹新生代和老生帶的GC策略及組合方式,。
新生代 – 串行GC(Serial Copying)
算法:復(fù)制(Copy)
過程:
1. 掃描出新生代中存活的對(duì)象;
2. Minor GC將存活的對(duì)象復(fù)制到做為To Space的S0/S1區(qū),;
3. 之前做為To Space/From Spache的S0/S1區(qū)對(duì)換角色,;
4. 經(jīng)歷過幾次Minor GC仍然存活的對(duì)象,放入老生代,。
新生代 – 并行回收GC(Parallel Scavenge)
算法:復(fù)制(Copy)
過程:在掃描和復(fù)制時(shí)均采用多線程方式進(jìn)行(如下圖),,并且并行回收GC為大的新生代回收做了很多優(yōu)化(可以自行擴(kuò)展閱讀相關(guān)資料)。
優(yōu)勢(shì):在多CPU的機(jī)器上其GC耗時(shí)會(huì)比串行方式短,,適合多CPU,、對(duì)暫停時(shí)間要求較短的應(yīng)用。
配置方式:本身是Server級(jí)別多CPU機(jī)器上的默認(rèn)GC方式,,也可以通過-XX:+UseParallelGC來指定,,并且可以采用-XX:ParallelGCThread來指定線程數(shù)。
新生代 – 并行GC(ParNew)
算法:復(fù)制(Copy)
過程:與并行回收GC(Parallel Scavenge)的區(qū)別在于并行GC(ParNew)必須配合老生代使用CMS GC,。原因是CMS GC在進(jìn)行老生代GC時(shí),,有些過程是并發(fā)執(zhí)行的。如果此時(shí)發(fā)生了Minor GC,,需要進(jìn)行相應(yīng)處理,,而并行回收GC(Parallel Scavenge)是沒有做這些處理的。也正是如此,,ParNew GC不可與并行的老生代GC同時(shí)使用,。
配置方式:在配置為CMS GC的情況下,新生代默認(rèn)使用并行GC(ParNew)方式,,也可以通過-XX:+UseParNewGC來指定,。
老生代 – 串行GC(Serial MSC)
算法:Mark-Sweep-Compact,該算法結(jié)合Mark-Sweep和Mark-Compact做了一些改進(jìn),。
過程:
1. 掃描出老生代中存活的對(duì)象,,進(jìn)行標(biāo)識(shí);
2. 遍歷整個(gè)老生代和持久代內(nèi)存空間,,找出未被標(biāo)識(shí)的對(duì)象,,并回收其內(nèi)存;
3. 進(jìn)行滑動(dòng)壓縮(Sliding Compaction),將存活對(duì)象向老生代空間的開始處滑動(dòng),,最終留出一塊連續(xù)的到結(jié)尾的內(nèi)存空間,。
優(yōu)缺點(diǎn):串行執(zhí)行的過程中為單線程,需要暫停應(yīng)用并耗時(shí)較長(zhǎng),。
配置方式:是client模式默認(rèn)采用的GC方式,,也可以通過-XX:UseSerialGC進(jìn)行指定。
老生代 – 并行GC(Parallel Mark Sweep,、Parallel Compacting)
算法:Mark -Compact
過程:
1. 將老生代劃分為并行線程個(gè)數(shù)的區(qū)域(regions),;
2. 并行進(jìn)行存活對(duì)象掃描和標(biāo)記;
3. 單線程對(duì)各區(qū)域進(jìn)行掃描,,標(biāo)記需要壓縮移動(dòng)的區(qū)域,;
4. 并行進(jìn)行對(duì)象移動(dòng)和區(qū)域不存活對(duì)象的回收。
優(yōu)缺點(diǎn):多線程同時(shí)操作以及dense prefix優(yōu)化,,會(huì)縮短應(yīng)用暫停時(shí)間,。但由于老生代較大,在掃描和標(biāo)識(shí)對(duì)象上需要花費(fèi)較長(zhǎng)時(shí)間,。
配置方式:通過-XX:+UseParallelGC來指定使用Parallel Mark Sweep,;通過-XX:UseParallelOldGC來指定使用Parallel Compacting。
老生代 – 并發(fā)GC(CMS:Concurrent Mark-Sweep GC)
算法:Mark –Sweep
過程:
1. 第一次標(biāo)記(Initial Marking):暫停整個(gè)應(yīng)用,,掃描從根集合點(diǎn)到老生代中可直接訪問到的對(duì)象,,并進(jìn)行標(biāo)記;
2. 并發(fā)標(biāo)記(Concurrent Marking):恢復(fù)所有應(yīng)用的線程,,同時(shí)開始并發(fā)對(duì)之前標(biāo)記過的對(duì)象進(jìn)行輪循,,以標(biāo)記這些對(duì)象可訪問的對(duì)象;
3. 重新標(biāo)記(Remark):暫停整個(gè)應(yīng)用,,掃描在第二步中被改變引用關(guān)系或新創(chuàng)建的對(duì)象,,并進(jìn)行標(biāo)記;
4. 并發(fā)收集(Concurrent Sweeping):恢復(fù)所有應(yīng)用的線程,,將沒有標(biāo)記的對(duì)象進(jìn)行單線程回收,。針對(duì)內(nèi)存碎片,CMS會(huì)盡量將相鄰的塊重新組裝成一個(gè)塊,。
優(yōu)缺點(diǎn):如上圖,,優(yōu)點(diǎn)是只有在第一次標(biāo)記和重新標(biāo)記階段需要暫停整個(gè)應(yīng)用,所以能夠做到影響應(yīng)用響應(yīng)時(shí)間很短,。缺點(diǎn)是并發(fā)標(biāo)記和并發(fā)收集階段CMS會(huì)與應(yīng)用線程爭(zhēng)用CPU資源(用增量CMS模式可以緩解),,并且容易產(chǎn)生內(nèi)存碎片,,free-list機(jī)制會(huì)導(dǎo)致Minor GC效率下降,。
配置方法:通過-XX:UseConcMarkSweepGC來啟動(dòng)老生代CMS GC;通過-XX:+UseCMSCompactAtFullCollection來啟動(dòng)內(nèi)存碎片整理功能(整理也會(huì)暫停應(yīng)用)。
4.Sun JDK GC默認(rèn)策略及組合策略
ü Clinet,、Server模式默認(rèn)GC策略
|
新生代GC方式
|
舊生代和持久代GC方式
|
Client
|
串行GC
|
串行GC
|
Server
|
并行回收GC
|
Parallel
Mark Sweep GC
|
ü Sun JDK GC組合方式
|
新生代GC
|
舊生代和持久代GC
|
-XX:+UseSerialGC
|
串行GC
|
串行GC
|
-XX:+UseParallelGC
|
并行回收GC
|
Parallel
Mark Sweep GC
|
-XX:+UseConcMarkSweepGC
|
并行GC
|
并發(fā)GC
當(dāng)出現(xiàn)Concurrent Mode Failure時(shí)采用串行GC
|
-XX:+UseParNewGC
|
并行GC
|
串行GC
|
-XX:+UseParallelOldGC
|
并行回收GC
|
Parallel
Mark Conpact
|
-XX:+UseConcMarkSweepGC
-XX:-UseParNewGC
|
串行GC
|
并發(fā)GC
當(dāng)出現(xiàn)Concurrent Mode Failure或Promotion Failed時(shí)采用串行GC
|
不支持的組合方式
|
1.-XX:+UseParNewGC
-XX:+UseParallelOldGC
2.-XX:+UseParNewGC
-XX:+UseSerialGC
|
|