前言
垃圾:簡(jiǎn)單說就是內(nèi)存中已經(jīng)不在被使用到的內(nèi)存空間就是垃圾。
垃圾回收(Garbage Collection,GC):顧名思義就是釋放垃圾占用的空間,防止內(nèi)存泄露。有效的使用可以使用的內(nèi)存严衬,對(duì)內(nèi)存堆中已經(jīng)死亡的或者長(zhǎng)時(shí)間沒有使用的對(duì)象進(jìn)行清除和回收。
Java 語言出來之前笆呆,大家都在拼命的寫 C 或者 C++ 的程序,而此時(shí)存在一個(gè)很大的矛盾,C++ 等語言創(chuàng)建對(duì)象要不斷的去開辟空間吩抓,不用的時(shí)候又需要不斷的去釋放空間蝗敢,既要寫構(gòu)造函數(shù)效床,又要寫析構(gòu)函數(shù),很多時(shí)候都在重復(fù)的 allocated,然后不停的析構(gòu)。于是嫌套,有人就提出,能不能寫一段程序?qū)崿F(xiàn)這塊功能圾旨,每次創(chuàng)建踱讨,釋放空間的時(shí)候復(fù)用這段代碼,而無需重復(fù)的書寫呢砍的?
1960年痹筛,基于 MIT 的 Lisp 首先提出了垃圾回收的概念,用于處理C語言等不停的析構(gòu)操作廓鞠,而這時(shí) Java 還沒有出世呢帚稠!所以實(shí)際上 GC 并不是Java的專利,GC 的歷史遠(yuǎn)遠(yuǎn)大于 Java 的歷史诫惭!
Java 垃圾回收機(jī)制
垃圾回收主要關(guān)注 Java 堆
Java 內(nèi)存運(yùn)行時(shí)區(qū)域中的程序計(jì)數(shù)器翁锡、虛擬機(jī)棧蔓挖、本地方法棧隨線程而生滅夕土;棧中的棧幀隨著方法的進(jìn)入和退出而有條不紊地執(zhí)行著出棧和入棧操作。每一個(gè)棧幀中分配多少內(nèi)存基本上是在類結(jié)構(gòu)確定下來時(shí)就已知的(盡管在運(yùn)行期會(huì)由 JIT 編譯器進(jìn)行一些優(yōu)化)瘟判,因此這幾個(gè)區(qū)域的內(nèi)存分配和回收都具備確定性怨绣,不需要過多考慮回收的問題,因?yàn)榉椒ńY(jié)束或者線程結(jié)束時(shí)拷获,內(nèi)存自然就跟隨著回收了篮撑。
而 Java 堆不一樣,一個(gè)接口中的多個(gè)實(shí)現(xiàn)類需要的內(nèi)存可能不一樣匆瓜,一個(gè)方法中的多個(gè)分支需要的內(nèi)存也可能不一樣赢笨,我們只有在程序處于運(yùn)行期間時(shí)才能知道會(huì)創(chuàng)建哪些對(duì)象,這部分內(nèi)存的分配和回收都是動(dòng)態(tài)的驮吱,垃圾收集器所關(guān)注的是這部分內(nèi)存茧妒。
怎么定義垃圾
引用計(jì)數(shù)算法(Reachability Counting)
通過在對(duì)象頭中分配一個(gè)空間來保存該對(duì)象被引用的次數(shù)(Reference Count)。如果該對(duì)象被其它對(duì)象引用左冬,則它的引用計(jì)數(shù)加1桐筏,如果刪除對(duì)該對(duì)象的引用,那么它的引用計(jì)數(shù)就減1拇砰,當(dāng)該對(duì)象的引用計(jì)數(shù)為0時(shí)梅忌,那么該對(duì)象就會(huì)被回收狰腌。
- 優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單、效率高牧氮。
-
缺點(diǎn):不能解決對(duì)象之間循環(huán)引用的問題琼腔。
循環(huán)引用問題
可達(dá)性分析算法(根搜索算法)
可達(dá)性分析算法(Reachability Analysis)的基本思路是,通過一些被稱為引用鏈(GC Roots)的對(duì)象作為起點(diǎn)踱葛,從這些節(jié)點(diǎn)開始向下搜索展姐,搜索走過的路徑被稱為(Reference Chain),當(dāng)一個(gè)對(duì)象到 GC Roots 沒有任何引用鏈相連時(shí)(即從 GC Roots 節(jié)點(diǎn)到該節(jié)點(diǎn)不可達(dá))剖毯,則證明該對(duì)象是不可用的圾笨。
在 Java 語言中,可作為 GC Root 的對(duì)象包括以下4種:
虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象
方法區(qū)中類靜態(tài)屬性引用的對(duì)象
方法區(qū)中常量引用的對(duì)象
本地方法棧中 JNI(即一般說的 Native 方法)引用的對(duì)象
Java虛擬機(jī)內(nèi)部的引用逊谋,如基本數(shù)據(jù)類型對(duì)應(yīng)的Class對(duì)象擂达,一些常駐的異常對(duì)象(NPE),類加載器等等
所有被同步鎖持有的對(duì)象
反應(yīng)Java虛擬機(jī)內(nèi)部情況的JMXBean,JVMTI中注冊(cè)的回調(diào)胶滋,本地代碼緩存等
目前的主流Java虛擬機(jī)使用的都是準(zhǔn)確式GC板鬓,HotSpot虛擬機(jī)使用了一組叫做OopMap的數(shù)據(jù)結(jié)構(gòu)以達(dá)到準(zhǔn)確式GC的目的。
在HotSpot中究恤,對(duì)象的類型信息里有記錄自己的OopMap俭令,記錄了在該類型的對(duì)象內(nèi)什么偏移量上是什么類型的數(shù)據(jù)。所以從對(duì)象開始向外的掃描可以是準(zhǔn)確的部宿;這些數(shù)據(jù)是在類加載過程中計(jì)算得到的抄腔。
-
每個(gè)被JIT編譯過后的方法也會(huì)在一些特定的位置記錄下OopMap,記錄了執(zhí)行到該方法的某條指令的時(shí)候理张,棧上和寄存器里哪些位置是引用赫蛇。這樣GC在掃描棧的時(shí)候就會(huì)查詢這些OopMap就知道哪里是引用了。這些特定的位置主要在:
- 1雾叭、循環(huán)的末尾
- 2悟耘、方法臨返回前 / 調(diào)用方法的call指令后
- 3、可能拋異常的位置
在OopMap的協(xié)助下织狐,JVM可以很快的做完GC Roots枚舉暂幼,但是JVM并沒有為每一條指令生成一個(gè)OopMap。
記錄OopMap的這些"特定位置"被稱為安全點(diǎn)(safepoint)移迫,即當(dāng)前線程執(zhí)行到安全點(diǎn)后才允許暫停進(jìn)行GC旺嬉。
如果一段代碼中,對(duì)象引用關(guān)系不會(huì)發(fā)生變化起意,這個(gè)區(qū)域中任何地方開始GC都是安全的鹰服,那么這個(gè)區(qū)域稱為安全區(qū)域。
引用分類
StrongReference: 強(qiáng)引用
強(qiáng)引用是使用最普遍的引用。如果一個(gè)對(duì)象具有強(qiáng)引用悲酷,那垃圾回收器絕不會(huì)回收它套菜。當(dāng)內(nèi)存空間不足,Java 虛擬機(jī)寧愿拋出 OutOfMemoryError 錯(cuò)誤设易,使程序異常終止逗柴,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來解決內(nèi)存不足的問題。
public class Main {
public static void main(String[] args) {
new Main().fun1();
}
public void fun1() {
Object object = new Object();
Object[] objArr = new Object[1000];
}
}
SoftReference: 軟引用
軟引用是用來描述一些有用但并不是必需的對(duì)象顿肺,在 Java 中用 java.lang.ref.SoftReference
類來表示戏溺。對(duì)于軟引用關(guān)聯(lián)著的對(duì)象,只有在內(nèi)存不足的時(shí)候 JVM 才會(huì)回收該對(duì)象屠尊。因此旷祸,這一點(diǎn)可以很好地用來解決 OOM 的問題,并且這個(gè)特性很適合用來實(shí)現(xiàn)緩存:比如網(wǎng)頁緩存讼昆、圖片緩存等托享。
軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被JVM回收浸赫,這個(gè)軟引用就會(huì)被加入到與之關(guān)聯(lián)的引用隊(duì)列中闰围。下面是一個(gè)使用示例:
import java.lang.ref.SoftReference;
public class Main {
public static void main(String[] args) {
SoftReference<String> sr = new SoftReference<String>(new String("hello"));
System.out.println(sr.get());
}
}
WeakReference: 弱引用
弱引用與軟引用的區(qū)別在于:只具有弱引用的對(duì)象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中既峡,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象羡榴,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存运敢。不過校仑,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象者冤。
import java.lang.ref.WeakReference;
public class Main {
public static void main(String[] args) {
WeakReference<String> sr = new WeakReference<String>(new String("hello"));
System.out.println(sr.get());
System.gc(); //通知JVM的gc進(jìn)行垃圾回收
System.out.println(sr.get());
}
}
PhantomReference: 虛引用
“虛引用”也稱為幽靈引用或幻影引用肤视,顧名思義,就是形同虛設(shè)涉枫,與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期腐螟。如果一個(gè)對(duì)象僅持有虛引用愿汰,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收乐纸。虛引用和前面的軟引用衬廷、弱引用不同,它并不影響對(duì)象的生命周期汽绢。在 Java 中用 java.lang.ref.PhantomReference
類表示吗跋。如果一個(gè)對(duì)象與虛引用關(guān)聯(lián),則跟沒有引用與之關(guān)聯(lián)一樣,在任何時(shí)候都可能被垃圾回收器回收跌宛。要注意的是酗宋,虛引用必須和引用隊(duì)列關(guān)聯(lián)使用,當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí)疆拘,如果發(fā)現(xiàn)它還有虛引用蜕猫,就會(huì)把這個(gè)虛引用加入到與之 關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入了虛引用哎迄,來了解被引用的對(duì)象是否將要被垃圾回收回右。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)漱挚。
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
public class Main {
public static void main(String[] args) {
ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
System.out.println(pr.get());
}
}
跨代引用
跨代引用:也就是一個(gè)代中的對(duì)象引用另一個(gè)代中的對(duì)象翔烁。
跨代引用假說:跨代引用相對(duì)于同代引用來說只是極少數(shù)。
隱含推論:存在互相引用關(guān)系的兩個(gè)對(duì)象旨涝,是應(yīng)該傾向于同時(shí)生存或同時(shí)消亡租漂。
記憶集
記憶集(Remembered Set):一種用于記錄從非收集區(qū)域指向收集區(qū)域的指針集合的抽象數(shù)據(jù)結(jié)構(gòu)。
記憶集記錄精讀
不考慮效率和成本颊糜,最簡(jiǎn)單的實(shí)現(xiàn)可以用非收集區(qū)域中所有含跨代引用的對(duì)象數(shù)組哩治。但空間開銷大,成本高衬鱼。
在垃圾收集的場(chǎng)景中业筏,收集器只需要通過記憶集判斷出某一塊非收集區(qū)域是否存在有指向了收集區(qū)域的指針,故選擇更粗狂的顆粒記錄鸟赫,可供選擇的有字節(jié)精讀蒜胖、對(duì)象精讀、卡精讀(卡表)抛蚤。
字節(jié)精讀:每個(gè)記錄精確到一個(gè)機(jī)器字長(zhǎng)台谢,該字節(jié)包含跨代指針。
對(duì)象精度:每個(gè)記錄精確到一個(gè)對(duì)象岁经,該對(duì)象里有字段含有跨代指針朋沮。
卡精度:每個(gè)記錄精確到一塊內(nèi)存區(qū)域,該區(qū)域內(nèi)有對(duì)象含有跨代指針缀壤。
卡表(Card Table):是記憶集的一種具體實(shí)現(xiàn)樊拓,它定義了記憶集的記錄精度、與堆內(nèi)存的映射關(guān)系等塘慕〗钕模卡表最簡(jiǎn)單的形式可以只是一個(gè)字節(jié)數(shù)組。
卡表的每個(gè)元素都對(duì)應(yīng)著其標(biāo)識(shí)的內(nèi)存區(qū)域中一塊特定大小的內(nèi)存塊图呢,這個(gè)內(nèi)存塊稱為卡頁(Card Page)条篷。
寫屏障(write barrier)
寫屏障就是對(duì)一個(gè)對(duì)象引用進(jìn)行寫操作(即引用賦值)之前或之后附加執(zhí)行的邏輯骗随。
通過寫屏障來實(shí)現(xiàn)當(dāng)對(duì)象狀態(tài)改變后,維護(hù)卡表狀態(tài)赴叹。
寫屏障與記憶集
每次在對(duì)一個(gè)對(duì)象引用進(jìn)行賦值的時(shí)候鸿染,會(huì)產(chǎn)生一個(gè)寫屏障中斷操作,然后檢查將要寫入的引用指向的對(duì)象是否和該引用當(dāng)前指向的對(duì)象處在不同的region中稚瘾;如果不同牡昆,通過CardTable將相關(guān)的引用信息記錄到Remembered set中;當(dāng)進(jìn)行垃圾收集時(shí)摊欠,在GC根節(jié)點(diǎn)的枚舉范圍內(nèi)加入Remembered Set丢烘,就可以保證不用進(jìn)行全局掃描。
判斷是否垃圾的步驟
1些椒、如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒有與 GC Roots 相連接的引用鏈播瞳,那它將會(huì)被第一次標(biāo)記并且進(jìn)行一次篩選,篩選的條件是此對(duì)象是否有必要執(zhí)行 finalize() 方法免糕。
當(dāng)對(duì)象沒有覆蓋 finalize() 方法赢乓,或者 finalize() 方法已經(jīng)被虛擬機(jī)調(diào)用過,虛擬機(jī)將這兩種情況都視為“沒有必要執(zhí)行”石窑,直接進(jìn)行第二次標(biāo)記牌芋。
兩個(gè)步驟走完后,如果任然沒有使用松逊,那就屬于垃圾躺屁。
如果這個(gè)對(duì)象被判定為有必要執(zhí)行 finalize() 方法,那么這個(gè)對(duì)象將會(huì)放置在一個(gè)叫做 F-Queue 的隊(duì)列之中经宏,并在稍后由一個(gè)由虛擬機(jī)自動(dòng)建立的犀暑、低優(yōu)先級(jí)的 Finalizer 線程去執(zhí)行它。
這里所謂的“執(zhí)行”是指虛擬機(jī)會(huì)觸發(fā)這個(gè)方法烁兰,但并不承諾會(huì)等待它運(yùn)行結(jié)束耐亏,因?yàn)槿绻粋€(gè)對(duì)象在 finalize() 方法中執(zhí)行緩慢,將很可能會(huì)一直阻塞 F-Queue 隊(duì)列沪斟,甚至導(dǎo)致整個(gè)內(nèi)存回收系統(tǒng)崩潰广辰。
GC類型
MinorGC/YoungGC:發(fā)生在新生代的收集動(dòng)作。
MajorGC/OldGC:發(fā)生在老年代的GC币喧,目前只有CMS收集器會(huì)有單獨(dú)收集老年代的行為轨域。
MixedGC:收集整個(gè)新生代以及部分老年代,目前只有G1收集器會(huì)有這種行為杀餐。
FullGC:收集整個(gè)Java堆和方法區(qū)的GC。
Stop The World
Java中Stop-The-World機(jī)制簡(jiǎn)稱STW朱巨,Java中一種全局暫褪非蹋現(xiàn)象,多半由于GC引起。所謂全局停頓琼讽,就是所有Java代碼停止運(yùn)行必峰,native代碼可以執(zhí)行,但不能與JVM交互钻蹬。
其危害是長(zhǎng)時(shí)間服務(wù)停止吼蚁,沒有響應(yīng);對(duì)于HA系統(tǒng)可能引起主備切換问欠,嚴(yán)重危害生產(chǎn)環(huán)境肝匆。
目前垃圾收集器的優(yōu)化方向基本上都是在盡量減少或者縮短Stop The World的時(shí)間。
jvm-Stop the world:https://blog.csdn.net/jakeswang/article/details/107673734
垃圾收集類型
串行收集:GC單線程內(nèi)存回收顺献,會(huì)暫停所有的用戶線程旗国,如:Serial
并行收集:多個(gè)GC線程并發(fā)工作,此時(shí)用戶線程是暫停的注整,如:Parallel
并發(fā)收集:用戶線程和GC線程同時(shí)執(zhí)行(不一定是并行能曾,可能交替執(zhí)行),不需要暫停用戶線程肿轨,如:CMS
判斷類無用條件
JVM中該類的所有實(shí)例都已經(jīng)被回收寿冕。
加載該類的ClassLoader已經(jīng)被回收。
沒有任何地方引用該類的Class對(duì)象椒袍。
無法在任何地方通過反射訪問這個(gè)類驼唱。
垃圾收集算法
Mark-Sweep: 標(biāo)記-清除算法
這是最基礎(chǔ)的算法,就像它名字一樣槐沼,算法分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象(如哪些內(nèi)存需要回收所描述的對(duì)象)曙蒸,對(duì)標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象,如下圖所示:
優(yōu)點(diǎn):簡(jiǎn)單岗钩。
缺點(diǎn):
- 一個(gè)是效率問題纽窟,標(biāo)記和清除兩個(gè)過程的效率都不高。
- 另一個(gè)是空間問題兼吓,標(biāo)記清除后會(huì)產(chǎn)生大量的不連續(xù)的內(nèi)存碎片臂港,可能會(huì)導(dǎo)致后續(xù)無法分配大對(duì)象而導(dǎo)致再一次觸發(fā)垃圾收集動(dòng)作。
Copying: 復(fù)制算法
為了針對(duì)標(biāo)記-清除算法的不足视搏,復(fù)制算法將可用內(nèi)存容量劃分為大小相等的兩塊审孽,每次只使用一塊。當(dāng)一塊的內(nèi)存用完了浑娜,就將還存活的對(duì)象復(fù)制到另一塊上面去佑力。然后把已使用過的內(nèi)存空間一次清理掉,如下圖所示:
優(yōu)點(diǎn):實(shí)現(xiàn)簡(jiǎn)單筋遭,運(yùn)行高效打颤,不用考慮內(nèi)存碎片問題暴拄。
缺點(diǎn):使用內(nèi)存比原來縮小了一半。
現(xiàn)在的商業(yè)虛擬機(jī)都采用這種收集算法來回收新生代编饺,有企業(yè)分析的得出其實(shí)并不需求將內(nèi)存按1:1的比例劃分乖篷,因?yàn)樾律械膶?duì)象大部分都是“朝生夕死”的。所以透且,HotSpot虛擬機(jī)默認(rèn)的Eden和Survivor的大小比例是8:1撕蔼。一塊Eden和兩塊Survivor,每次使用一塊Eden和一塊Survivor秽誊,也就是說只有10%是浪費(fèi)的鲸沮。如果另一塊Survivor都無法存放上次垃圾回收的對(duì)象時(shí),那這些對(duì)象將通過“擔(dān)保機(jī)制”進(jìn)入老年代了养距。
擔(dān)保機(jī)制—分配擔(dān)保
當(dāng)新生代進(jìn)行垃圾回收后诉探,新生代的存活區(qū)放置不下或Eden區(qū)放置不下新的大對(duì)象,那么需要把這些對(duì)象放置到老年代去的策略棍厌,也就是老年代為新生代的GC做空間分配擔(dān)保肾胯,步驟如下:
- 1、在發(fā)生MinorGC前耘纱,JVM會(huì)檢查老年代的最大可用的連續(xù)空間敬肚,是否大于新生代所有的對(duì)象的總空間,如果大于束析,可以確保M inorGC是安全的艳馒。
- 2、如果小于员寇,那么JVM會(huì)檢查是否設(shè)置了允許擔(dān)保失敗弄慰,如果允許,則繼續(xù)檢查老年代最大可用的連續(xù)空間蝶锋,是否大于歷次晉升到老年代對(duì)象的平均大小陆爽。
- 3、如果大于扳缕,則嘗試進(jìn)行一次MinorGC慌闭。
- 4、如果不大于躯舔,則該做一次FullGC驴剔。
Mark-Compact: 標(biāo)記-整理算法
復(fù)制算法的高效性是建立在存活對(duì)象少、垃圾對(duì)象多的前提下的粥庄。這種情況在年輕代經(jīng)常發(fā)生丧失,但是在老年代更常見的情況是大部分對(duì)象都是存活對(duì)象。如果依然使用復(fù)制算法惜互,由于存活的對(duì)象較多利花,復(fù)制的成本也將很高科侈。
標(biāo)記-整理算法和標(biāo)記-清除算法差不多载佳,都是一開始對(duì)回收對(duì)象進(jìn)行標(biāo)記炒事,但后續(xù)不是直接對(duì)對(duì)象清理,而是讓所有存活的對(duì)象都向一端移動(dòng)蔫慧,然后直接清理掉端邊界以外的內(nèi)存挠乳,如下圖所示:
分代收集算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根據(jù)對(duì)象存活的生命周期將內(nèi)存劃分為若干個(gè)不同的區(qū)域姑躲。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation)睡扬,老年代的特點(diǎn)是每次垃圾收集時(shí)只有少量對(duì)象需要被回收,而新生代的特點(diǎn)是每次垃圾回收時(shí)都有大量的對(duì)象需要被回收黍析,那么就可以根據(jù)不同代的特點(diǎn)采取最適合的收集算法卖怜。
垃圾收集器
垃圾收集算法只是內(nèi)存回收的方法,垃圾收集器是來具體實(shí)現(xiàn)這些算法并實(shí)現(xiàn)內(nèi)存回收的阐枣。
不同廠商马靠、不同版本的虛擬機(jī)實(shí)現(xiàn)差別很大,HotSpot中包含的收集器如下圖所示:
注: 當(dāng)老年代配了 CMS收集器時(shí), 如果內(nèi)存使用率超過了一定的比例, 系統(tǒng)會(huì)拋出 Concurrent Mode Failure蔼两,此時(shí)會(huì)自動(dòng)采用 Serial Old收集器做 Full GC甩鳄。
1、紅色虛線在 Jdk8時(shí), 將Serial與 CMS的組合和ParNew與 Serial Old的組合聲明為廢棄, 并在 Jdk9時(shí)完全棄用了额划。
2妙啃、黃色虛線在 Jdk14時(shí), 棄用了 Parallel Scavenge與 Serial Old的組合。
3俊戳、綠色虛線在 Jdk14時(shí), 完全棄用了 CMS垃圾收集器揖赴。
近期垃圾收集器發(fā)展過程
- Jdk1.7u4開始全面支持 G1垃圾收集器。
- Jdk9時(shí) G1成為了抑胎,默認(rèn)的垃圾收集器, 替代了 CMS. (CMS聲明為廢棄)燥滑。
- Jdk10時(shí) G1垃圾收集器,實(shí)現(xiàn)了并行性來改善了最壞情況下的延遲圆恤。
- Jdk11時(shí)引入了 Epsilon垃圾收集器突倍,又稱為 No-Op(無操作)收集器。同時(shí)盆昙,引入了 ZGC(The Z Garbage Collector)羽历,Oracle公司的可伸縮的低延遲垃圾收集器。
- Jdk12時(shí)增強(qiáng)了G1垃圾收集器淡喜,自動(dòng)返回未用的堆內(nèi)存給操作系統(tǒng)秕磷。同時(shí),引入 OpenJDK引入了炼团,紅帽公司開發(fā)的 Shenandoah GC低延遲垃圾收集器(試驗(yàn)性階段)
- Jdk13時(shí)增強(qiáng)了 ZGC澎嚣,自動(dòng)返回未用堆內(nèi)存給操作系統(tǒng)疏尿。
- Jdk14時(shí)完全棄用了 CMS垃圾收集器(如果顯式設(shè)置會(huì)提示警告,但不會(huì)中斷易桃。而會(huì)自動(dòng)選擇默認(rèn)收集器就是 G1)褥琐。擴(kuò)展了 ZGC在 MacOS和 Windows上的應(yīng)用。
具體組合如下:
Young | Tenured | JVM options | Description |
---|---|---|---|
Serial | Serial Old | -XX:+UseSerialGC | 單線程進(jìn)行GC晤郑,適合單CPU或小內(nèi)存敌呈,單機(jī)程序 |
Serial | CMS+SerialOld | -XX:-UseParNewGC -XX:+UseConcMarkSweepGC | CMS進(jìn)行GC失敗時(shí),會(huì)自動(dòng)使用Serial Old 策略進(jìn)行GC造寝;JDK8中聲明為廢棄 |
Parallel Scavenge | Serial Old | -XX:+UseParallelGC | Jdk1.5及之前版本的搭配使用 |
Parallel Scavenge | Parallel Old | -XX:+UseParallelGC -XX:+UseParallelOldGC | 適合多CPU磕洪,需要最大吞吐量,如后臺(tái)計(jì)算型應(yīng)用诫龙;是JDK8默認(rèn)收集器策略 |
Parallel New | Serial Old | -XX:+UseParNewGC | JDK8中聲明為廢棄 |
Parallel New | CMS+SerialOld | -XX:+UseParNewGC -XX:+UseConcMarkSweepGC | 適合多CPU析显,追求低停頓時(shí)間,需快速響應(yīng)如互聯(lián)網(wǎng)應(yīng)用 |
G1 | -XX:+UseG1GC | JDK9默認(rèn)收集器 | |
ZGC | -XX:+UseZGC |
垃圾收集算法有:復(fù)制算法签赃、標(biāo)記-清除算法谷异、標(biāo)記-整理算法。
1姊舵、串行垃圾回收器
串行的垃圾收集器有兩種晰绎,Serial與Serial Old,一般兩者搭配使用括丁。是單線程收集器荞下,在垃圾收集時(shí),會(huì)Stop The World史飞。
優(yōu)點(diǎn)是簡(jiǎn)單尖昏,對(duì)于單CPU,由于沒有多線程的交互開銷构资,可能更高效抽诉,是默認(rèn)的Client模式下的新生代收集器。
通過-XX:+UseSerialGC開啟吐绵,會(huì)使用Serial+Serial Old的收集器組合迹淌。
新生代采用Serial,是利用復(fù)制算法己单;老年代使用Serial Old采用標(biāo)記-整理算法唉窃。
2、并行垃圾回收器
ParNew(并行)收集器:使用多線程進(jìn)行垃圾回收纹笼,在垃圾收集時(shí)纹份,會(huì)Stop The World。
在并發(fā)能力好的cpu環(huán)境里面,它停頓的時(shí)間要比串行收集器短蔓涧,但對(duì)于單cpu或并發(fā)能力較弱的CPU件已,由于多線程的交互開銷,可能比串行收集器更差元暴。
是Server模式下首選的新生代收集器篷扩,且能和CMS收集器配合使用。
默認(rèn)開啟的收集線程數(shù)和cpu數(shù)量一樣昨寞,運(yùn)行數(shù)量可以通過修改-XX:ParallelGCThreads設(shè)定瞻惋。用于新生代收集,復(fù)制算法援岩。
使用-XX:+UseParNewGC,和Serial Old收集器組合進(jìn)行內(nèi)存回收掏导。
使用CMS默認(rèn)開啟ParNew享怀。
3、新生代Parallel Scavenge收集器
新生代Parallel Scavenge收集器:是一個(gè)用于新生代的趟咆、使用復(fù)制算法的添瓷、并行的收集器。
跟ParNew很類似值纱,但更關(guān)注吞吐量鳞贷,吞吐量?jī)?yōu)先,吞吐量=代碼運(yùn)行時(shí)間/(代碼運(yùn)行時(shí)間+垃圾收集時(shí)間)虐唠,也就是高效率利用cpu時(shí)間搀愧,盡快完成程序的運(yùn)算任務(wù)可以設(shè)置最大停頓時(shí)間MaxGCPauseMillis以及,吞吐量大小GCTimeRatio疆偿。
通過-XX:+UseParallelGC開啟咱筛,Server模式下默認(rèn)提供了其和SerialOld進(jìn)行搭配的分代收集方式。
通過-XX:+UseParallelOldGC參數(shù)使用Parallel Scavenge + Parallel Old器組合進(jìn)行內(nèi)存回收杆故。
-XX:MaxGCPauseMillis:設(shè)置GC的最大停頓時(shí)間迅箩。
-XX:GCTimeRatio:設(shè)置吞吐量大小。
-XX:+UseAdaptiveSizePolicy:設(shè)置了該參數(shù)处铛,則隨著GC,會(huì)動(dòng)態(tài)調(diào)整新生代的大小饲趋,Eden,Survivor比例等,以提供最合適的停頓時(shí)間或者最大的吞吐量撤蟆。
4奕塑、CMS收集器
CMS( Concurrent Mark-Sweep 并發(fā)標(biāo)記清除)收集器是一種以獲得最短回收停頓時(shí)間為目標(biāo)的收集器。從名字就能直到其是給予標(biāo)記-清除算法的枫疆。但是它比一般的標(biāo)記-清除算法要復(fù)雜一些锡宋,分為以下4個(gè)階段:
- 初始標(biāo)記:標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,會(huì)“Stop The World”东亦。
- 并發(fā)標(biāo)記:GC Roots Tracing,可以和用戶線程并發(fā)執(zhí)行扒披。
- 重新標(biāo)記:標(biāo)記期間產(chǎn)生的對(duì)象存活的再次判斷,修正對(duì)這些對(duì)象的標(biāo)記圃泡,執(zhí)行時(shí)間相對(duì)并發(fā)標(biāo)記短碟案,會(huì)“Stop The World”。
- 并發(fā)清除:清除對(duì)象,可以和用戶線程并發(fā)執(zhí)行颇蜡。
優(yōu)點(diǎn):低停頓价说,并發(fā)執(zhí)行。
-
缺點(diǎn):
- 1风秤、并發(fā)執(zhí)行鳖目,對(duì)CPU資源壓力大。
- 2缤弦、無法處理在處理過程中產(chǎn)生的垃圾领迈,可能導(dǎo)致FullGC。
- 3碍沐、由于它是基于標(biāo)記-清除算法的狸捅,那么就無法避免空間碎片的產(chǎn)生。CMS收集器無法處理浮動(dòng)垃圾(Floating Garbage)累提,可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生尘喝。
所謂浮動(dòng)垃圾,在CMS并發(fā)清理階段用戶線程還在運(yùn)行著斋陪,伴隨程序運(yùn)行自然還會(huì)有新的垃圾不斷產(chǎn)生朽褪,這一部分垃圾出現(xiàn)在標(biāo)記過程之后,CMS無法在當(dāng)次收集中處理掉它們鳍贾,只能留待下一次GC時(shí)再清理掉鞍匾。
參數(shù)設(shè)置
- -XX:+UseConcMarkSweepGC:使用ParNew+CMS+Serial Old的收集器組合。Serial Old將作為CMS出錯(cuò)的后備收集器骑科。
- -XX:CMSInitiatingOccupancyFraction:指定當(dāng)年老代空間滿了多少后進(jìn)行垃圾回收橡淑,默認(rèn)80%。
- -XX:+UseCMSCompactAtFullCollection:(默認(rèn)是開啟的)在CMS收集器頂不住要進(jìn)行FullGC時(shí)開啟內(nèi)存碎片整理過程咆爽,該過程需要STW梁棠。
- -XX:CMSFullGCsBeforeCompaction:指定多少次FullGC后才進(jìn)行整理。
- -XX:ParallelCMSThreads:指定CMS回收線程的數(shù)量斗埂,默認(rèn)為:(CPU數(shù)量+3)/4符糊。
G1收集器
把G1單獨(dú)拿出來的原因是其比較復(fù)雜,在JDK 1.7確立是項(xiàng)目目標(biāo)呛凶,在JDK 7u2版本之后發(fā)布男娄,并在JDK 9中成為了默認(rèn)的垃圾回收器。通過“-XX:+UseG1GC”啟動(dòng)參數(shù)即可指定使用G1 GC。
- G1從整體看還是基于標(biāo)記-清除算法的模闲,但是局部上是基于復(fù)制算法的建瘫。這樣就意味者它空間整合做的比較好,因?yàn)椴粫?huì)產(chǎn)生空間碎片尸折。
- G1還是并發(fā)與并行的啰脚,它能夠充分利用多CPU、多核的硬件環(huán)境來縮短“stop the world”的時(shí)間实夹。
- G1還是分代收集的橄浓,但是G1不再像上文所述的垃圾收集器,需要分代配合不同的垃圾收集器亮航,因?yàn)镚1中的垃圾收集區(qū)域是“分區(qū)”(Region)的荸实。G1的分代收集和以上垃圾收集器不同的就是除了有年輕代的ygc,全堆掃描的full GC外塞赂,還有包含所有年輕代以及部分老年代Region的Mixed GC泪勒。
- G1還可預(yù)測(cè)停頓,通過調(diào)整參數(shù)宴猾,制定垃圾收集的最大停頓時(shí)間。
- G1跟蹤各個(gè)Region里面垃圾堆的價(jià)值大小叼旋,在后臺(tái)維護(hù)一個(gè)優(yōu)先列表仇哆,每次根據(jù)允許的時(shí)間來回收價(jià)值最大的區(qū)域,從而保證在有限時(shí)間內(nèi)的高效收集夫植。
G1收集器的運(yùn)作大致可以分為以下步驟:初始標(biāo)記讹剔、并發(fā)標(biāo)記、最終標(biāo)記详民、篩選回收延欠。
- 初始標(biāo)記階段:僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,并且修改TAMS(Next Top at Mark Set)的值沈跨,讓下一個(gè)階段用戶程序并發(fā)運(yùn)行時(shí)由捎,能在正確可用的Region中創(chuàng)建新對(duì)象,這個(gè)階段需要STW饿凛,但耗時(shí)很短狞玛。
- 并發(fā)標(biāo)記階段:從GC Roots開始對(duì)堆中對(duì)象進(jìn)行可達(dá)性分析,找到存活的對(duì)象涧窒,這階段耗時(shí)較長(zhǎng)心肪,但是可以和用戶線程并發(fā)運(yùn)行。
- 最終標(biāo)記階段:是為了修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變化的那一部分標(biāo)記記錄纠吴,虛擬機(jī)將這段時(shí)間對(duì)象變化記錄在線程Remembered Set Logs里面硬鞍,最終標(biāo)記需要把Remembered Set Logs的數(shù)據(jù)合并到Remembered Sets中,這階段需要暫停線程,但是可并行執(zhí)行固该。
- 篩選回收階段:首先對(duì)各個(gè)Region的回收價(jià)值和成本進(jìn)行排序锅减,根據(jù)用戶所期望的GC停頓時(shí)間來確定回收計(jì)劃。
G1收集器運(yùn)行示意圖如下圖所示蹬音。
G1分區(qū)的概念
G1的堆區(qū)在分代的基礎(chǔ)上上煤,引入分區(qū)的概念。G1將堆分成了若干Region,以下和”分區(qū)”代表同一概念著淆。(這些分區(qū)不要求是連續(xù)的內(nèi)存空間)Region的大小可以通過G1HeapRegionSize參數(shù)進(jìn)行設(shè)置劫狠,其必須是2的冪,范圍允許為1Mb到32Mb永部。 JVM的會(huì)基于堆內(nèi)存的初始值和最大值的平均數(shù)計(jì)算分區(qū)的尺寸独泞,平均的堆尺寸會(huì)分出約2000個(gè)Region。分區(qū)大小一旦設(shè)置苔埋,則啟動(dòng)之后不會(huì)再變化懦砂。如下圖簡(jiǎn)單畫了下G1分區(qū)模型。
Eden regions(年輕代-Eden區(qū))
Survivor regions(年輕代-Survivor區(qū))
Old regions(老年代)
Humongous regions(巨型對(duì)象區(qū)域)
Free regions(未分配區(qū)域组橄,也會(huì)叫做可用分區(qū))-上圖中空白的區(qū)域
G1中的巨型對(duì)象是指荞膘,占用了Region容量的50%以上的一個(gè)對(duì)象。Humongous區(qū)玉工,就專門用來存儲(chǔ)巨型對(duì)象羽资。如果一個(gè)H區(qū)裝不下一個(gè)巨型對(duì)象,則會(huì)通過連續(xù)的若干H分區(qū)來存儲(chǔ)遵班。因?yàn)榫扌蛯?duì)象的轉(zhuǎn)移會(huì)影響GC效率屠升,所以并發(fā)標(biāo)記階段發(fā)現(xiàn)巨型對(duì)象不再存活時(shí),會(huì)將其直接回收狭郑。ygc也會(huì)在某些情況下對(duì)巨型對(duì)象進(jìn)行回收腹暖。
分區(qū)可以有效利用內(nèi)存空間,因?yàn)槭占w是使用“標(biāo)記-整理”翰萨,Region之間基于“復(fù)制”算法脏答,GC后會(huì)將存活對(duì)象復(fù)制到可用分區(qū)(未分配的分區(qū)),所以不會(huì)產(chǎn)生空間碎片缨历。
G1參數(shù)設(shè)置:
- -XX:+UseG1GC:使用 G1 (Garbage First) 垃圾收集器
- -XX:MaxGCPauseMillis=n:設(shè)置最大GC停頓時(shí)間(GC pause time)指標(biāo)(target)以蕴,這是一個(gè)軟性指標(biāo)(soft goal),JVM 會(huì)盡量去達(dá)成這個(gè)目標(biāo)辛孵。
- -XX:InitiatingHeapOccupancyPercent=n:堆空間占用了多少(百分比)的時(shí)候觸發(fā)GC丛肮,默認(rèn)值為 45。
- -XX:NewRatio=n:新生代與老生代(new/old generation)的大小比例(Ratio)魄缚,默認(rèn)值為 2宝与。
- -XX:SurvivorRatio=n:eden/survivor 空間大小的比例(Ratio)焚廊,默認(rèn)值為 8。
- -XX:MaxTenuringThreshold=n:新生代到老年代的對(duì)象年齡习劫,默認(rèn)值為 15咆瘟。
- -XX:ParallelGCThreads=n:設(shè)置垃圾收集器在并行階段使用的線程數(shù),默認(rèn)值隨JVM運(yùn)行的平臺(tái)不同而不同诽里。
- -XX:ConcGCThreads=n:并發(fā)垃圾收集器使用的線程數(shù)量袒餐,默認(rèn)值隨JVM運(yùn)行的平臺(tái)不同而不同。
- -XX:G1ReservePercent=n:設(shè)置作為空閑空間的預(yù)留內(nèi)存百分比谤狡,以降低目標(biāo)空間溢出的風(fēng)險(xiǎn)灸眼,默認(rèn)值是10%。
- -XX:G1HeapRegionSize=n:設(shè)置G1區(qū)域的大小墓懂,值是2的次冪焰宣,范圍是1MB到32MB,目標(biāo)是根據(jù)最小的Java堆大小劃分出約2048個(gè)區(qū)域捕仔。
G1 GC的分類和過程
JDK10 之前的G1中的GC只有Young GC匕积,Mixed GC。Full GC處理會(huì)交給單線程的Serial Old垃圾收集器榜跌。
Young GC年輕代收集
在分配一般對(duì)象(非巨型對(duì)象)時(shí)闪唆,當(dāng)所有Eden region使用達(dá)到最大閥值并且無法申請(qǐng)足夠內(nèi)存時(shí),會(huì)觸發(fā)一次Young GC钓葫。每次Young GC會(huì)回收所有Eden以及Survivor區(qū)苞氮,并且將存活對(duì)象復(fù)制到Old區(qū)以及另一部分的Survivor區(qū)。到Old區(qū)的標(biāo)準(zhǔn)就是在PLAB中得到的計(jì)算結(jié)果瓤逼。因?yàn)閅oung GC會(huì)進(jìn)行根掃描,所以會(huì)stop the world库物。
Young GC的回收過程如下:
1霸旗、根掃描,跟CMS類似,Stop the world戚揭,掃描GC Roots對(duì)象诱告。
2、處理Dirty card,更新RSet.
3民晒、掃描RSet,掃描RSet中所有old區(qū)對(duì)掃描到的young區(qū)或者survivor去的引用精居。
4、拷貝掃描出的存活的對(duì)象到survivor2/old區(qū)
5潜必、處理引用隊(duì)列靴姿,軟引用,弱引用磁滚,虛引用
Mix GC混合收集
Mixed GC是G1 GC特有的佛吓,跟Full GC不同的是Mixed GC只回收部分老年代的Region宵晚。哪些old region能夠放到CSet里面,有很多參數(shù)可以控制维雇。比如G1HeapWastePercent參數(shù)淤刃,在一次young GC之后,可以允許的堆垃圾百占比吱型,超過這個(gè)值就會(huì)觸發(fā)mixed GC逸贾。
G1MixedGCLiveThresholdPercent參數(shù)控制的,old代分區(qū)中的存活對(duì)象比津滞,達(dá)到閥值時(shí)铝侵,這個(gè)old分區(qū)會(huì)被放入CSet。
Mixed GC一般會(huì)發(fā)生在一次Young GC后面,為了提高效率据沈,Mixed GC會(huì)復(fù)用Young GC的全局的根掃描結(jié)果哟沫,因?yàn)檫@個(gè)Stop the world過程是必須的,整體上來說縮短了暫停時(shí)間锌介。
Mix GC的回收過程可以理解為Young GC后附加的全局concurrent marking嗜诀,全局的并發(fā)標(biāo)記主要用來處理old區(qū)(包含H區(qū))的存活對(duì)象標(biāo)記,過程如下:
- 初始標(biāo)記(Initial Mark)孔祸。標(biāo)記GC Roots隆敢,會(huì)STW,一般會(huì)復(fù)用Young GC的暫停時(shí)間。如前文所述崔慧,初始標(biāo)記會(huì)設(shè)置好所有分區(qū)的NTAMS值拂蝎。
- 根分區(qū)掃描(Root Region Scan)。這個(gè)階段GC的線程可以和應(yīng)用線程并發(fā)運(yùn)行惶室。其主要掃描初始標(biāo)記以及之前Young GC對(duì)象轉(zhuǎn)移到的Survivor分區(qū)温自,并標(biāo)記Survivor區(qū)中引用的對(duì)象。所以此階段的Survivor分區(qū)也叫根分區(qū)(Root Region)皇钞。
- 并發(fā)標(biāo)記(Concurrent Mark)悼泌。會(huì)并發(fā)標(biāo)記所有非完全空閑的分區(qū)的存活對(duì)象,也即使用了SATB算法夹界,標(biāo)記各個(gè)分區(qū)馆里。
- 最終標(biāo)記(Remark)。主要處理SATB緩沖區(qū)可柿,以及并發(fā)標(biāo)記階段未標(biāo)記到的漏網(wǎng)之魚(存活對(duì)象)鸠踪,會(huì)STW,可以參考上文的SATB處理。
- 清除階段(Clean UP)复斥。上述SATB也提到了营密,會(huì)進(jìn)行bitmap的swap,以及PTAMS,NTAMS互換永票。整理堆分區(qū)卵贱,調(diào)整相應(yīng)的RSet(比如如果其中記錄的Card中的對(duì)象都被回收滥沫,則這個(gè)卡片的也會(huì)從RSet中移除),如果識(shí)別到了完全空的分區(qū),則會(huì)清理這個(gè)分區(qū)的RSet键俱。這個(gè)過程會(huì)STW兰绣。
清除階段之后,還會(huì)對(duì)存活對(duì)象進(jìn)行轉(zhuǎn)移(復(fù)制算法)编振,轉(zhuǎn)移到其他可用分區(qū)缀辩,所以當(dāng)前的分區(qū)就變成了新的可用分區(qū)。復(fù)制轉(zhuǎn)移主要是為了解決分區(qū)內(nèi)的碎片問題踪央。
Full GC
G1在對(duì)象復(fù)制/轉(zhuǎn)移失敗或者沒法分配足夠內(nèi)存(比如巨型對(duì)象沒有足夠的連續(xù)分區(qū)分配)時(shí)臀玄,會(huì)觸發(fā)Full GC。Full GC使用的是stop the world的單線程的Serial Old模式畅蹂,所以一旦觸發(fā)Full GC則會(huì)STW應(yīng)用線程健无,并且執(zhí)行效率很慢。JDK 8版本的G1是不提供Full GC的處理的液斜。對(duì)于G1 GC的優(yōu)化累贤,很大的目標(biāo)就是沒有Full GC。
ZGC收集器
ZGC是一款在JDK11中新加入的具有實(shí)驗(yàn)性質(zhì)的低延遲垃圾收集器少漆,目前僅支持Linux/x86-64臼膏。
ZGC的設(shè)計(jì)目標(biāo)是:支持TB級(jí)內(nèi)存容量,暫停時(shí)間低(<10ms)示损,對(duì)整個(gè)程序吞吐量的影響小于15%渗磅。
ZGC收集器是一款基于Region內(nèi)存布局的,(暫時(shí))不設(shè)分代的检访,使用了讀屏障始鱼、染色指針和內(nèi)存多重映射等技術(shù)來實(shí)現(xiàn)可并發(fā)的標(biāo)記-整理算法的,以低延遲為首要目標(biāo)的一款垃圾收集器脆贵。
GC性能指標(biāo)
- 吞吐量:應(yīng)用花在非GC上的時(shí)間百分比风响,應(yīng)用代碼執(zhí)行時(shí)間/運(yùn)行的總時(shí)間。
- GC負(fù)荷:與吞吐量相反丹禀,指應(yīng)用花在GC上的時(shí)間百分比,GC時(shí)間/運(yùn)行的總時(shí)間鞋怀。
- 暫停時(shí)間:應(yīng)用花在GC stop-the-world的時(shí)間双泪。
- GC頻率:就是GC在一個(gè)時(shí)間段發(fā)生的次數(shù)。
- 反應(yīng)速度:從一個(gè)對(duì)象變成垃圾到這個(gè)對(duì)象被回收的時(shí)間密似。
- 交互式的應(yīng)用要求暫停時(shí)間越少越好焙矛。
GC觸發(fā)條件
- Minor GC觸發(fā)條件:Eden區(qū)滿時(shí)
-
- Full GC觸發(fā)條件:
- 調(diào)用System.gc時(shí),系統(tǒng)建議執(zhí)行Full GC残腌,但是不必然執(zhí)行
- 老年代空間不足
- 方法區(qū)空間不足
- 通過Minor GC后進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存
- 由Eden區(qū)村斟、From Space區(qū)向To Space區(qū)復(fù)制時(shí)贫导,對(duì)象大小大于To Space可用內(nèi)存,則把該對(duì)象轉(zhuǎn)存到老年代蟆盹,且老年代的可用內(nèi)存小于該對(duì)象大小孩灯。
JVM內(nèi)存容量配置原則
-
新生代盡可能設(shè)置大點(diǎn),如果太小會(huì)導(dǎo)致:
- YGC次數(shù)更加頻繁
- 可能導(dǎo)致YGC對(duì)象直接進(jìn)入老年代逾滥,如果此時(shí)老年代滿了峰档,會(huì)觸發(fā)FGC。
-
對(duì)老年代寨昙,針對(duì)響應(yīng)時(shí)間有限應(yīng)用:由于老年代通常采用并發(fā)收集器讥巡,因此其大小要綜合考慮并發(fā)量和并發(fā)持續(xù)時(shí)間等參數(shù)。
- 如果設(shè)置小了舔哪,可能會(huì)造成內(nèi)存碎片欢顷,高回收頻率會(huì)導(dǎo)致應(yīng)用暫停。
- 如果設(shè)置大了捉蚤,會(huì)增加回收的時(shí)間抬驴。
對(duì)老年代,針對(duì)吞吐量?jī)?yōu)先的應(yīng)用:通常設(shè)置較大的新生代和較小的老年代外里,這樣可以盡可能回收大部分短期對(duì)象怎爵,減少中期對(duì)象,而老年代盡量存放長(zhǎng)期存活的對(duì)象盅蝗。
依據(jù)對(duì)象的存活周期進(jìn)行分類鳖链,對(duì)象優(yōu)先在新生代分配,長(zhǎng)時(shí)間存活的的對(duì)象進(jìn)入老年代墩莫。
根據(jù)不同代的特點(diǎn)芙委,選取合適的收集算法:少量對(duì)象存活,適合復(fù)制算法狂秦;大量對(duì)象存活灌侣,適合標(biāo)記清除或標(biāo)記整理算法。
參考:
https://zhuanlan.zhihu.com/p/73628158
https://www.cnblogs.com/czwbig/p/11127159.html
https://segmentfault.com/a/1190000010463373
https://blog.csdn.net/iva_brother/article/details/87886525
http://blog.itpub.net/69906029/viewspace-2654005/
https://www.cnblogs.com/lfs2640666960/p/8522588.html
https://www.cnblogs.com/lsgxeva/p/10231201.html
https://www.cnblogs.com/blythe/p/7488061.html
https://www.cnblogs.com/jimoer/p/13170249.html
https://blog.51cto.com/u_11440114/5103211
https://blog.csdn.net/lovewangyihui/article/details/122442440