JVM——垃圾回收

前言

  • 垃圾:簡(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)記,過程如下:

    1. 初始標(biāo)記(Initial Mark)孔祸。標(biāo)記GC Roots隆敢,會(huì)STW,一般會(huì)復(fù)用Young GC的暫停時(shí)間。如前文所述崔慧,初始標(biāo)記會(huì)設(shè)置好所有分區(qū)的NTAMS值拂蝎。
    1. 根分區(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)皇钞。
    1. 并發(fā)標(biāo)記(Concurrent Mark)悼泌。會(huì)并發(fā)標(biāo)記所有非完全空閑的分區(qū)的存活對(duì)象,也即使用了SATB算法夹界,標(biāo)記各個(gè)分區(qū)馆里。
    1. 最終標(biāo)記(Remark)。主要處理SATB緩沖區(qū)可柿,以及并發(fā)標(biāo)記階段未標(biāo)記到的漏網(wǎng)之魚(存活對(duì)象)鸠踪,會(huì)STW,可以參考上文的SATB處理。
    1. 清除階段(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ā)條件

    1. Minor GC觸發(fā)條件:Eden區(qū)滿時(shí)
    1. 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

https://www.cnblogs.com/xinay/p/16625707.html

https://www.cnblogs.com/sudokill/p/16961673.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末裂问,一起剝皮案震驚了整個(gè)濱河市侧啼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌堪簿,老刑警劉巖痊乾,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異椭更,居然都是意外死亡哪审,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門虑瀑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來湿滓,“玉大人滴须,你說我怎么就攤上這事∵窗拢” “怎么了扔水?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)而线。 經(jīng)常有香客問我铭污,道長(zhǎng),這世上最難降的妖魔是什么膀篮? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任嘹狞,我火速辦了婚禮,結(jié)果婚禮上誓竿,老公的妹妹穿的比我還像新娘磅网。我一直安慰自己,他們只是感情好筷屡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布涧偷。 她就那樣靜靜地躺著,像睡著了一般毙死。 火紅的嫁衣襯著肌膚如雪燎潮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天扼倘,我揣著相機(jī)與錄音确封,去河邊找鬼。 笑死再菊,一個(gè)胖子當(dāng)著我的面吹牛爪喘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纠拔,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼秉剑,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了稠诲?” 一聲冷哼從身側(cè)響起侦鹏,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎臀叙,沒想到半個(gè)月后种柑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匹耕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荠雕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片稳其。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驶赏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出既鞠,到底是詐尸還是另有隱情煤傍,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布嘱蛋,位于F島的核電站蚯姆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏洒敏。R本人自食惡果不足惜龄恋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凶伙。 院中可真熱鬧郭毕,春花似錦、人聲如沸函荣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽傻挂。三九已至乘碑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間金拒,已是汗流浹背兽肤。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留殖蚕,地道東北人轿衔。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像睦疫,于是被迫代替她去往敵國(guó)和親害驹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • JVM 垃圾回收 寫在前面 本節(jié)常見面試題 問題答案在文中都有提到 如何判斷對(duì)象是否死亡(兩種方法)蛤育。 簡(jiǎn)單的介紹...
    Guide哥閱讀 245評(píng)論 0 0
  • 常用的GC算法 1.引用計(jì)數(shù)法 給一個(gè)對(duì)象添加一個(gè)引用計(jì)數(shù)器宛官,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器的值就加1瓦糕,當(dāng)引用失效...
    eliter0609閱讀 518評(píng)論 0 3
  • 本文主要講述JVM中幾種常見的垃圾回收算法和相關(guān)的垃圾回收器底洗,以及常見的和GC相關(guān)的性能調(diào)優(yōu)參數(shù)。 GC Root...
    4ea0af17fd67閱讀 284評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月咕娄,有人笑有人哭亥揖,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,536評(píng)論 28 53
  • 信任包括信任自己和信任他人 很多時(shí)候费变,很多事情摧扇,失敗、遺憾挚歧、錯(cuò)過扛稽,源于不自信,不信任他人 覺得自己做不成滑负,別人做不...
    吳氵晃閱讀 6,190評(píng)論 4 8