Java垃圾回收

java JVM內(nèi)部結(jié)構(gòu)

JVM Components
memory.png

java對(duì)象創(chuàng)建過(guò)程

/**
 * 
 * 關(guān)于Java對(duì)象創(chuàng)建的過(guò)程:
 * new關(guān)鍵字創(chuàng)建對(duì)象的3個(gè)步驟:
 * 1.在堆內(nèi)存中創(chuàng)建出對(duì)象的實(shí)例插龄。
 * 2.為對(duì)象的實(shí)例成員變量賦初值度帮。
 * 3.將對(duì)象的引用返回
 * 指針碰撞(前提是堆中的空間通過(guò)一個(gè)指針進(jìn)行分割,一側(cè)是已經(jīng)被占用的空間述呐,另一側(cè)是未被占用的空間)
 * 空閑列表(前提是堆內(nèi)存空間中已被使用與未被使用的空間是交織在一起的,這時(shí)疹吃,虛擬機(jī)就需要通過(guò)一個(gè)列表來(lái)記錄哪些空間是可以使用的,
 * 哪些空間是已被使用的西雀,接下來(lái)找出可以容納下新創(chuàng)建對(duì)象的且未被使用的空間萨驶,在此空間存放該對(duì)象,同時(shí)還要修改列表上的記錄)
 * 對(duì)象在內(nèi)存中的布局:
 * 1.對(duì)象頭.
 * 2.實(shí)例數(shù)據(jù)(即我們?cè)谝粋€(gè)類(lèi)中所聲明的各項(xiàng)信息)
 * 3.對(duì)齊填充(可選) !
 * 引用訪問(wèn)對(duì)象的方式:
 * 1.使用句柄的方式艇肴。
 * 2.使用直接指針的方式腔呜。
 */
public class MemoryTest1 {
    public static void main(String[] args) {
        //-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError 設(shè)置jvm對(duì)空間最小和最大以及遇到錯(cuò)誤時(shí)把堆存儲(chǔ)文件打印出來(lái)
        //打開(kāi)jvisualvm裝在磁盤(pán)上的轉(zhuǎn)存文件
        List<MemoryTest1> list = new ArrayList<>();
        while (true) {
            list.add(new MemoryTest1());
            System.gc();
        }
    }
}

虛擬機(jī)棧溢出測(cè)試

/**
 * 
 * 虛擬機(jī)棧溢出測(cè)試
 */
public class MemoryTest2 {

    private int length;

    public int getLength() {
        return length;
    }

    public void test() throws InterruptedException {
        length++;
        Thread.sleep(1);
        test();
    }

    public static void main(String[] args) {
        //測(cè)試調(diào)整虛擬機(jī)棧內(nèi)存大小為:  -Xss160k,此處除了可以使用JVisuale監(jiān)控程序運(yùn)行狀況外還可以使用jconsole
        MemoryTest2 memoryTest2 = new MemoryTest2();
        try {
            memoryTest2.test();
        } catch (Throwable e) {
            System.out.println(memoryTest2.getLength());//打印最終的最大棧深度為:2587
            e.printStackTrace();
        }
    }
}

元空間溢出測(cè)試

/**
 *
 * 元空間內(nèi)存溢出測(cè)試
 * 設(shè)置元空間大性俚俊:-XX:MaxMetaspaceSize=100m
 * 關(guān)于元空間參考:https://www.infoq.cn/article/java-permgen-Removed
 */
public class MemoryTest3 {
    public static void main(String[] args) {
        //使用動(dòng)態(tài)代理動(dòng)態(tài)生成類(lèi)
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MemoryTest3.class);
            enhancer.setUseCache(false);
            enhancer.setCallback((MethodInterceptor) (obj, method, ags, proxy) -> proxy.invokeSuper(obj, ags));
            System.out.println("Hello World");
            enhancer.create();// java.lang.OutOfMemoryError: Metaspace
        }
    }

JVM命令使用

/**
 *
 * jmam命令的使用 -clstats<pid>進(jìn)程id  to print class loader statistics
 * jmap -clstats 3740
 *
 * jstat -gc 3740
 *  S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
 * 512.0  512.0   0.0    0.0   24064.0   9626.0   86016.0     1004.1   4864.0 3758.2 512.0  409.1     144    0.064   0      0.000    0.064
 * MC元空間總大小核畴,MU元空間已使用的大小
 */
public class MemoryTest4 {
    public static void main(String[] args) {
        while (true)
            System.out.println("hello world");
    }
    //查看java進(jìn)程id jps -l
    // 使用jcmd查看當(dāng)前進(jìn)程的可用參數(shù):jcmd 10368 help
    //查看jvm的啟動(dòng)參數(shù) jcmd 10368 VM.flags
   // 10368:-XX:CICompilerCount=3 -XX:InitialHeapSize=132120576 -XX:MaxHeapSize=2111832064 -XX:MaxNewSize=703594496
    // -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44040192 -XX:OldSize=88080384 -XX:+UseCompressedClassPointers
    // -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

}

JVM常用命令

jcmd (從JDK 1. 7開(kāi)始增加的命令)
1. jcmd pid VM.flags: 查看JVM的啟動(dòng)參數(shù)
2. jcmd pid help: 列出當(dāng)前運(yùn)行的Java進(jìn)程可以執(zhí)行的操作
3. jcmd pid helpJFR.dump:查看具體命令的選項(xiàng)
4. jcmd pid PerfCounter.print:看JVm性能相關(guān)的參數(shù)
5. jcmd pid VM.uptime:查有JVM的啟動(dòng)時(shí)長(zhǎng)
6. jcmd pid GC.class_ histogram: 查看系統(tǒng)中類(lèi)的統(tǒng)計(jì)信息
7. jcmd pid Thread.print: 查看線程堆棧信息
8. jcmd pid GC.heap dump filename 導(dǎo)出Heap dump文件, 導(dǎo)出的文件可以通過(guò)jvisualvm查看
9. jcmd pid VM.system_ properties:查看JVM的屬性信息

JVM內(nèi)存舉例說(shuō)明

   public void method() {
        Object object = new Object();

        /*生成了2部分的內(nèi)存區(qū)域冲九,1)object這個(gè)引用變量谤草,因?yàn)?        是方法內(nèi)的變量,放到JVM Stack里面,2)真正Object
        class的實(shí)例對(duì)象莺奸,放到Heap里面
        上述 的new語(yǔ)句一共消耗12個(gè)bytes, JVM規(guī)定引用占4
        個(gè)bytes (在JVM Stack)丑孩, 而空對(duì)象是8個(gè)bytes(在Heap)
        方法結(jié)束后,對(duì)應(yīng)Stack中的變量馬上回收灭贷,但是Heap
        中的對(duì)象要等到GC來(lái)回收温学、*/
    }

JVM垃圾識(shí)別(根搜索算法( GC RootsTracing ))

  • 在實(shí)際的生產(chǎn)語(yǔ)言中(Java、 C#等)甚疟,都是使用根搜索算法判定對(duì)象是否存活仗岖。

  • 算法基本思路就是通過(guò)一系列的稱(chēng)為“GCRoots"的點(diǎn)作為起始進(jìn)行向下搜索,當(dāng)一個(gè)對(duì)象到GCRoots沒(méi)有任何引用鏈( Reference Chain)相連览妖,則證明此對(duì)象
    是不可用的

  • 在Java語(yǔ)言中轧拄,GC Roots包括
    ●在VM棧(幀中的本地變量)中的引用
    ●方法區(qū)中的靜態(tài)引用
    ●JNI (即一般說(shuō)的Native方法) 中的引用

方法區(qū)

  • Java虛擬機(jī)規(guī)范表示可以不要求虛擬機(jī)在這區(qū)實(shí)現(xiàn)GC,這區(qū)GC的“性價(jià)比”一般比較低
    在堆中,尤其是在新生代讽膏,常規(guī)應(yīng)用進(jìn)行I次GC一般可以回收70%~95%的空間紧帕,而方法區(qū)的GC效率遠(yuǎn)小于此

  • 當(dāng)前的商業(yè)JVM都有實(shí)現(xiàn)方法區(qū)的GC,主要回收兩部分內(nèi)容:廢棄常量與無(wú)用類(lèi)

  • 主要回收兩部分內(nèi)容:廢棄常量與無(wú)用類(lèi)

  • 類(lèi)回收需要滿足如下3個(gè)條件:

    • 該類(lèi)所有的實(shí)例都已經(jīng)被GC,也就是JVM中不存在該Class的任何實(shí)例
    • 加載該類(lèi)的ClassL oader已經(jīng)被GC
    • 該類(lèi)對(duì)應(yīng)的java.lang.Class對(duì)象沒(méi)有在任何地方被引用,如不能在任何地方通過(guò)反射訪問(wèn)該類(lèi)的方法
  • 在大量使用反射桅打、動(dòng)態(tài)代理是嗜、CGLib等字節(jié)碼框架、動(dòng)態(tài)生成JSP以及OSGi這類(lèi)頻繁自定義Classloader的場(chǎng)景都需要JVM具備類(lèi)卸載的支持以保證方法區(qū)不會(huì)溢出

垃圾判斷與GC算法

  • 垃圾判斷的算法

    • 引用計(jì)數(shù)算法(Reference Counting)
    • 根搜索算法( GC RootsTracing )
    • 在實(shí)際的生產(chǎn)語(yǔ)言中(Java挺尾、 C#等)都是使用根搜索算法判定對(duì)象是否存活
    • 算法基本思路就是通過(guò)一一系列的稱(chēng)為GCRoots"的點(diǎn)作為起始進(jìn)行向下搜索鹅搪,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈(Reference Chain)相連,則證明此對(duì)象是不可用的
  • 在Java語(yǔ)言中遭铺,可作為GC Roots的對(duì)象包括下面幾種:

    • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象丽柿。
    • 方法區(qū)中類(lèi)靜態(tài)屬性引用的對(duì)象恢准。
    • 方法區(qū)中常量引用的對(duì)象。
    • 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的對(duì)象
根搜索算法(Root Tracing)
  • 標(biāo)記-清除算法(Mark Sweep)
  • 標(biāo)記-整理算法(Mark-Compact)
  • 復(fù)制算法(Copying)
  • 分代算法(Generational)

標(biāo)記一清除算法(Mark-Sweep)

  • 算法分為“標(biāo)記”和“清除”兩個(gè)階段甫题,
    首先標(biāo)記出所有需要回收的對(duì)象馁筐,然后回
    收所有需要回收的對(duì)象

  • 缺點(diǎn)
    效率問(wèn)題,標(biāo)記和清理兩個(gè)過(guò)程效率都不高
    空間問(wèn)題坠非,
    標(biāo)記清理之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片敏沉,空間碎片太多可能會(huì)導(dǎo)致后續(xù)使用中無(wú)法找到足夠的連續(xù)內(nèi)存而提前觸發(fā)另一次的垃圾搜集動(dòng)作

  • 效率不高,需要掃描所有對(duì)象炎码。堆越大盟迟,GC越慢
    存在內(nèi)存碎片問(wèn)題。GC次數(shù)越多潦闲,碎片越為嚴(yán)重

標(biāo)記一清除算法(Mark-Sweep)

復(fù)制(Copying) 搜集算法

  • 將可用內(nèi)存劃分為兩塊攒菠,每次只使用其中的一塊,當(dāng)一半?yún)^(qū)內(nèi)存用完了歉闰,僅將還存活
    的對(duì)象復(fù)制到另外一塊上面辖众,然后就把原來(lái)整塊內(nèi)存空間一次性清理掉,

  • 這樣使得每次內(nèi)存回收都是對(duì)整個(gè)半?yún)^(qū)的回收和敬,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況赵辕,只要移動(dòng)堆頂指針,按順序分配內(nèi)存就可以了概龄,實(shí)現(xiàn)簡(jiǎn)單还惠,運(yùn)行高效。只是這種算法的代價(jià)是將內(nèi)存縮小為原來(lái)的一半私杜,代價(jià)高昂

  • 現(xiàn)在的商業(yè)虛擬機(jī)中都是用了這一種收集算法來(lái)回收新生代

  • 將內(nèi)存分為一塊較大的eden空間和2塊較少的survivor空間蚕键,每次使用eden和其中一塊
    survivor, 當(dāng)回收時(shí)將eden和survivor還存活的對(duì)象一次性拷 貝到另外一塊survivor空間上,然后清理掉eden和用過(guò)的survivor

  • Oracle Hotspot虛擬機(jī)默認(rèn)eden和survivor的大小比例是8:1衰粹,也就是每次只有10%的內(nèi)存是“浪費(fèi)”的

  • 復(fù)制收集算法在對(duì)象存活率高的時(shí)候锣光,效率有所下降

  • 如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保用于應(yīng)付半?yún)^(qū)內(nèi)存中所有對(duì)象都100%存活的極端情況铝耻,所以在老年代一般不能直接選用這種算法

復(fù)制(Copying) 搜集算法
  • 只需要掃描存活的對(duì)象誊爹,效率更高
  • 不會(huì)產(chǎn)生碎片
  • 需要浪費(fèi)額外的內(nèi)存作為復(fù)制區(qū)
  • 復(fù)制算法非常適合生命周期比較短的對(duì)象,因?yàn)槊看蜧C總能回收大部分的對(duì)象瓢捉,復(fù)制的開(kāi)銷(xiāo)比較小
  • 根據(jù)IBM的專(zhuān)i研究频丘,98%的Java對(duì)象只會(huì)存活1個(gè)GC周期,對(duì)這些對(duì)象很適合用復(fù)制算法泡态。而且
    不用1: 1的劃分工作區(qū)和復(fù)制區(qū)的空間

標(biāo)記一整理( Mark-Compact )算法

  • 標(biāo)記過(guò)程仍然樣搂漠,但后續(xù)步驟不是進(jìn)行直接清理,而是令所有存活的對(duì)象一端移動(dòng)某弦,然后直接清理掉這端邊界以外的內(nèi)存桐汤。

  • 沒(méi)有內(nèi)存碎片

  • 比Mark-Sweep耗費(fèi)更多的時(shí)間進(jìn)行compact

分代收集而克。( GenerationalCollecting)算法

  • 當(dāng)前商業(yè)虛擬機(jī)的垃圾收集都是采用“分代收集”( Generational Collecting)算法,根據(jù)對(duì)象不同的存活周期將內(nèi)存劃分為幾塊怔毛。
  • 一般是把Java堆分作新生代和老年代员萍,這樣就可以根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴ǎ┤缧律看蜧C都有大批對(duì)象死去拣度,只有少量存活碎绎,那就選用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本蜡娶,就可以完成收集。

Hotspot JVM 6中共劃分為三個(gè)代:

  • 年輕代(Young Generation)
  • 老年代(Old Generation)和
  • 永久代( Permanent Generation)
Hotspot JVM 6中共劃分為三個(gè)代
  • 年輕代(Young Generation)
    新生成的對(duì)象都放在新生代映穗。年輕代用復(fù)制算法進(jìn)行GC (理論上年輕代對(duì)象的生命周期非常短窖张,所以適合復(fù)制算法)

  • 年輕代分三個(gè)區(qū)。一個(gè)Eden區(qū)蚁滋,兩個(gè)Survivor區(qū)(可以通過(guò)參數(shù)設(shè)置Survivor個(gè)數(shù))宿接。對(duì)象在Eden區(qū)中生成。當(dāng)Eden區(qū)滿時(shí)辕录,還存活的對(duì)象將被復(fù)制到一個(gè)Survivor區(qū)睦霎,當(dāng)這個(gè)Survivor區(qū)滿時(shí),此區(qū)的存活對(duì)象將被復(fù)制到另外一個(gè)Survivor區(qū)走诞,當(dāng)?shù)诙€(gè)Survivor區(qū)也滿了的時(shí)候副女,從第一個(gè)Survivor區(qū)復(fù)制過(guò)來(lái)的并且此時(shí)還存活的對(duì)象,將被復(fù)制到老年代蚣旱。2個(gè)Survivor是完全對(duì)稱(chēng)碑幅,輪流替換。

  • Eden和2個(gè)Survivor的缺省比例是8:1:1塞绿,也就是10%的空間會(huì)被
    浪費(fèi)沟涨。可以根據(jù)GClog的信息調(diào)整大小的比例

  • 老年代(Old Generation)

    • 存放了經(jīng)過(guò)一次或多次GC還存活的對(duì)象
    • 一般采用Mark-Sweep或者M(jìn)ark-Compact算法進(jìn)行GC
    • 有多種垃圾收集器可以選擇异吻。每種垃圾收集器可以看作一個(gè)GC算法的具體實(shí)現(xiàn)裹赴。可以根據(jù)具體應(yīng)用的需求選用合適的垃圾收集器(追求吞吐量?追求最短的響應(yīng)時(shí)間?)
  • 永久代

    • 并不屬于堆(Heap).但是GC也會(huì)涉及到這個(gè)區(qū)域
    • 存放了每個(gè)Class的結(jié)構(gòu)信息诀浪, 包括常量池棋返、字段描述、方法描述雷猪。與垃圾收集要收集的Java對(duì)象關(guān)系不大

內(nèi)存分配與回收

  • 堆上分配
    大多數(shù)情況在eden上分配懊昨,偶爾會(huì)直接在old上分配細(xì)節(jié)取決于GC的實(shí)現(xiàn)

  • 棧上分配
    原子類(lèi)型的局部變量

  • GC要做的是將那些dead的對(duì)象所占用的內(nèi)存回收掉

    • Hotspot認(rèn)為沒(méi)有引用的對(duì)象是dead的
    • Hotspot將引用分為四種: Strong、 Soft春宣、Weak酵颁、Phantom
      Strong 即默認(rèn)通過(guò)Object o=new Object()這種方式賦值的引用
      Soft嫉你、Weak、 Phantom這 三種則都是繼承Reference
  • 在Full GC時(shí)會(huì)對(duì)Reference類(lèi)型的引用進(jìn)行特殊處理

    • Soft:內(nèi)存不夠時(shí)一定會(huì)被GC躏惋、長(zhǎng)期不用也會(huì)被GC
    • Weak: - 定會(huì)被GC幽污, 當(dāng)被mark為dead, 會(huì)在ReferenceQueue中通知
    • Phantom: 本來(lái)就沒(méi)引用,當(dāng)從jvm heap中釋放時(shí)會(huì)通知

垃圾回收器

垃圾回收器

GC回收的時(shí)機(jī)

  • 在分代模型的基礎(chǔ)上簿姨,GC從時(shí)機(jī)上分為兩種: Scavenge GC和Full GC
    • Scavenge GC (Minor GC)
      觸發(fā)時(shí)機(jī):新對(duì)象生成時(shí)距误,Eden空間滿了理論上Eden區(qū)大多數(shù)對(duì)象會(huì)在ScavengeGC回收,復(fù)制算法的執(zhí)
      行效率會(huì)很高扁位,ScavengeGC時(shí)間比較短准潭。
    • Full GC
      對(duì)整個(gè)JVM進(jìn)行整理,包括Young域仇、Old 和Perm主要的觸發(fā)時(shí)機(jī): 1) Old滿了2) Perm滿了3) system.gc()效率很低刑然,盡量減少Full GC。

垃圾回收器(Garbage Collector)

  • 分代模型: GC的宏觀愿景;
  • 垃圾回收器: GC的具體實(shí)現(xiàn)
  • Hotspot JVM提供多種垃圾回收器暇务,我們需要根據(jù)具體應(yīng)用的需要采用不同的回收器
  • 沒(méi)有萬(wàn)能的垃圾回收器泼掠,每種垃圾回收器都有自己的適用場(chǎng)景

垃圾收集器的‘并行”和并發(fā)

  • 并行(Parallel):指多個(gè)收集器的線程同時(shí)工作,但是用戶線程處于等待狀態(tài)
  • 并發(fā)(Concurrent):指收集器在工作的同時(shí)垦细,可以允許用戶線程工作择镇。并發(fā)不代表解決了GC停頓的問(wèn)題,在關(guān)鍵的步驟還是要停頓括改。比如在收集器標(biāo)記垃圾的時(shí)候腻豌。但在清除垃圾的時(shí)候,用戶線程可以和GC線程并發(fā)執(zhí)行嘱能。

Serial收集器

  • 最早的收集器饲梭,單線程進(jìn)行GC, New和Old Generation都可以使用焰檩,在新生代憔涉,采用復(fù)制算法;
  • 在老年代,采用Mark-Compact算法因?yàn)槭菃尉€程GC析苫,沒(méi)有多線程切換的額外開(kāi)銷(xiāo)兜叨,簡(jiǎn)單實(shí)用
    Hotspot Client模式默認(rèn)的收集器
Serial收集器

ParNew收集器

  • ParNew收集器就是Serial的多線程版本,除了使用多個(gè)收集線程外衩侥,其余行為包括算法国旷、STW、對(duì)象分配規(guī)則茫死、回收策略等都與Seria收集器一模一樣跪但。

  • 對(duì)應(yīng)的這種收集器是虛擬機(jī)運(yùn)行在Server模式的默認(rèn)新生代收集器,在單CPU的環(huán)境中峦萎,ParNew收集器并不會(huì)比Serial收集器有更好的效果

  • Serial收集器在新生代的多線程版本

  • 使用復(fù)制算法(因?yàn)獒槍?duì)新生代)只有在多CPU的環(huán)境下屡久,效率才會(huì)比Serial收集器高

  • 可以通過(guò)-XX:ParallelGC Threads來(lái)控制GC線程數(shù)的多少忆首。需要結(jié)合具體CPU的個(gè)數(shù)Server模式下新生代的缺省收集器

ParNew收集器

Parallel Scavenge收集器

  • Parallel Scavenge收集器也是一個(gè)多線程收集器,也是使用復(fù)制算法被环,但它的對(duì)象分配規(guī)則與回收策略都與ParNew收集器有所不同糙及,它是以吞吐量最大化(即GC時(shí)間占總運(yùn)行時(shí)間最小)為目標(biāo)的收集器實(shí)現(xiàn),它允許較長(zhǎng)時(shí)間的STW換取總吞吐量最大化

CMS ( Concurrent Mark Sweep )收集器

  • CMS是一種以最短停頓時(shí)間為目標(biāo)的收集器筛欢,使用CMS并不能達(dá)到GC效率最高(總體GC時(shí)間最小)浸锨,但它能盡可能降低GC時(shí)服務(wù)的停頓時(shí)間,CMS收集器使用的是標(biāo)記一清除算法

  • 特點(diǎn):

    • 追求最短停頓時(shí)間版姑,非常適合Web應(yīng)用
    • 只針對(duì)老年區(qū)柱搜,一般結(jié)合ParNew使用
    • Concurrent, GC線程和用戶線程并發(fā)工作(盡量并發(fā) )
    • Mark-Sweep
    • 只有在多CPU環(huán)境下才有意義
    • 使用-XX:+UseConcMarkSweepGC打開(kāi)
  • CMS收集器的缺點(diǎn)

    • CMS以犧牲CPU資源的代價(jià)來(lái)減少用戶線程的停頓。當(dāng)CPU個(gè)數(shù)少于4的時(shí)候剥险,有可能對(duì)吞吐量影響非常大
    • CMS在并發(fā)清理的過(guò)程中聪蘸,用戶線程還在跑。這時(shí)候需要預(yù)留一部分空間給用戶線程
    • CMS用Mark-Sweep,會(huì)帶來(lái)碎片問(wèn)題炒嘲。碎片過(guò)多的時(shí)候會(huì)容易頻繁觸發(fā)FullGC
CMS收集器

G1收集器

G1
  • heap被劃分為一個(gè)個(gè)相等的不連續(xù)的內(nèi)存區(qū)域(regions) 宇姚,每個(gè)region都有一個(gè)分代的角色: eden匈庭、 survivor夫凸、 old

  • 對(duì)每個(gè)角色的數(shù)量并沒(méi)有強(qiáng)制的限定,也就是說(shuō)對(duì)每種分代內(nèi)存的大小阱持,可以動(dòng)態(tài)變化

  • G1最大的特點(diǎn)就是高效的執(zhí)行回收夭拌,優(yōu)先去執(zhí)行那些大量對(duì)象可回收的區(qū)域(region)

  • G1使用了gc停頓可預(yù)測(cè)的模型,來(lái)滿足用戶設(shè)定的gc停頓時(shí)間衷咽,根據(jù)用戶設(shè)定的目標(biāo)時(shí)間鸽扁,G1會(huì)自動(dòng)地選擇哪些region要清除,次清除多少個(gè)region

  • G1從多個(gè)region中復(fù)制存活的對(duì)象镶骗,然后集中放入一個(gè)region中桶现,同時(shí)整理、清除內(nèi)存(copying收集算法)

  • 對(duì)比使用mark-sweep的CMS, G1使用的copying算法不會(huì)造成內(nèi)存碎片;

  • 對(duì)比Parallel Scavenge(基于copying )鼎姊、Parallel Old收集器(基于mark-compact-sweep)骡和,Parallel會(huì)對(duì)整個(gè)區(qū)域做整理導(dǎo)致gc停頓會(huì)比較長(zhǎng),而G1只是特定地整理幾個(gè)region相寇。

  • G1并非一個(gè)實(shí)時(shí)的收集器慰于,與parallelScavenge-樣,對(duì)gc停頓時(shí)間的設(shè)置并不絕對(duì)生效唤衫,只是G1有較高的幾率保證不超過(guò)設(shè)定的gc停頓時(shí)間婆赠。與之前的gc收集器對(duì)比,G1會(huì)根據(jù)用戶設(shè)定的gc停頓時(shí)間佳励,智能評(píng)估哪幾個(gè)region需要被回收可以滿足用戶的設(shè)定

分區(qū)(Region):

  • G1采取了不同的策略來(lái)解決并行休里、串行和CMS收集器的碎片蛆挫、暫停時(shí)間不可控等問(wèn)題一G1將 整個(gè)堆分成相同大小的分區(qū)(Region)

  • 每個(gè)分區(qū)都可能是年輕代也可能是老年代,但是在同份帐,時(shí)刻只能屬于某個(gè)代璃吧。年輕代、幸存區(qū)废境、老年代這些概念還存在畜挨,成為邏輯上的概念,這樣方便復(fù)用之前分代框架的邏輯噩凹。

  • 在物理巴元,上不需要連續(xù),則帶來(lái)了額外的好處有的分區(qū)內(nèi)垃圾對(duì)象特別多驮宴,有的分區(qū)內(nèi)垃圾對(duì)象很少逮刨,G1會(huì)優(yōu)先回收垃圾對(duì)象特別多的分區(qū),這樣可以花費(fèi)較少的時(shí)間來(lái)回收這些分區(qū)的垃圾堵泽,這也就是G1名字的由來(lái)修己,即首先收集垃圾最多的分區(qū)。

  • 依然是在新生代滿了的時(shí)候迎罗,對(duì)整個(gè)新生代進(jìn)行回收整個(gè)新生代中的對(duì)象睬愤,要么被回收、要么晉升纹安,至于新生代也采取分區(qū)機(jī)制的原因尤辱,則是因?yàn)檫@樣跟老年代的策略統(tǒng)一,方便調(diào)整代的大小

  • G1還是一種帶壓縮的收集器厢岂,在回收老年代的分區(qū)時(shí)光督,是將存活的對(duì)象從一個(gè)分區(qū)拷貝到另一個(gè)可用分區(qū),這個(gè)拷貝的過(guò)程就實(shí)現(xiàn)了局部的壓縮塔粒。

收集集合(CSet)

  • 一組可被回收的分區(qū)的集合结借。在CSet中存活的數(shù)據(jù)會(huì)在GC過(guò)程中被移動(dòng)到另一個(gè)可用分區(qū),CSet中的分區(qū)可以來(lái)自eden空間卒茬、survivor空間船老、 或者老年代

已記憶集合(RSet) :

  • RSet記錄了其他Region中的對(duì)象引用本Region中對(duì)象的關(guān)系,屬于points-into結(jié)構(gòu)( 誰(shuí)引用了我的對(duì)象)RSet的價(jià)值在于使得垃圾收集器不需要掃描整個(gè)堆找到誰(shuí)引用了當(dāng)前分區(qū)中的對(duì)象扬虚,只需要掃描RSet即可努隙。

  • Region1和Region3中的對(duì)象都引用了Region2中的對(duì)象,因此在Region2的RSet中記錄了這兩個(gè)引用辜昵。

region
  • G1 GC是在points-out的card table之上再加了一層結(jié)構(gòu)來(lái)構(gòu)成points-into RSet:每個(gè)region會(huì)記錄下到底哪些別的
    region有指向自己的指針荸镊,而這些指針?lè)謩e在哪些card的范圍內(nèi)。

  • 這個(gè)RSet其實(shí)是一個(gè)hash table,key是別的region的起始地址,value是一個(gè)集合躬存,里面的元素是card table的index.
    舉例來(lái)說(shuō)张惹,如果region A的RSet里有一項(xiàng)的key是region B,value里有index為1234的card,它的意思就是region B的
    一個(gè)card里 有引用指向region A岭洲。所以對(duì)region A來(lái)說(shuō)宛逗,該RSet記錄的是points-into的關(guān)系;而card table仍然記錄了points-out的關(guān)系。

  • Snapshot-AtThe-Beginning(SATB):SATB是G1 GC在并發(fā)標(biāo)記階段使用的增量式的標(biāo)記算法盾剩,

  • 并發(fā)標(biāo)記是并發(fā)多線程的雷激,但并發(fā)線程在同一時(shí)刻只掃描一個(gè)分區(qū)

參考鏈接:https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html

G1相對(duì)于CMS的優(yōu)勢(shì)

  • G1在壓縮空間方面有優(yōu)勢(shì)
  • G1通過(guò)將內(nèi)存空間分成區(qū)域(Region) 的方式避免內(nèi)存碎片問(wèn)題Eden、Survivor告私、 Old區(qū)不再固定屎暇,在內(nèi)存使用效率上來(lái)說(shuō)更靈活
  • G1可以通過(guò)設(shè)置預(yù)期停頓時(shí)間( Pause Time) 來(lái)控制垃圾收集時(shí)間,避免應(yīng)用雪崩現(xiàn)象
  • G1在回收內(nèi)存后會(huì)馬上同時(shí)做合并空閑內(nèi)存的工作驻粟,而CMS默認(rèn)是在STW ( stop the world) 的時(shí)候做
  • G1會(huì)在Young GC中使用根悼,而CMS只能在Old區(qū)使用

G1的適合場(chǎng)景

  • 服務(wù)端多核CPU、JVM內(nèi)存占用較大的應(yīng)用
  • 應(yīng)用在運(yùn)行過(guò)程中會(huì)產(chǎn)生大量?jī)?nèi)存碎片蜀撑、需要經(jīng)常壓縮空間
  • 想要更可控挤巡、可預(yù)期的GC停頓周期:防止高并發(fā)下應(yīng)用的雪崩現(xiàn)象

G1 GC模式

  • G1提供了兩種GC模式,Young GC和Mixed GC, 兩種都是完全Stop The World的

  • Young GC:選定所有年輕代里的Region酷麦。通過(guò)控制年輕代的Region個(gè)數(shù)矿卑,即年輕代內(nèi)存大小,來(lái)控制Young GC的時(shí)間開(kāi)銷(xiāo)贴铜。

  • Mixed GC:選定所有年輕代里的Region,外加根據(jù)global concurrent marking統(tǒng)計(jì)得出收集收益高的若干老年代Region粪摘。在用戶指定的開(kāi)銷(xiāo)目標(biāo)范圍內(nèi)盡可能選擇收益高的老年代Region

  • Mixed GC不是Full GC,它只能回收部分老年代的Region,如果Mixed GC實(shí)在無(wú)法跟上程序分配內(nèi)存的速度瀑晒,導(dǎo)致老年代填滿無(wú)法繼續(xù)進(jìn)行MixedGC绍坝,就會(huì)使用serialold GC (Full GC)來(lái)收集整個(gè)GC heap。所以本質(zhì)上苔悦,G1是不提供Full GC的

global concurrent marking

  • 初始標(biāo)記( initial mark, STW) :它標(biāo)記了從GCRoot開(kāi)始直接可達(dá)的對(duì)象轩褐。

  • 并發(fā)標(biāo)記( Concurrent Marking) :這個(gè)階段從GC Root開(kāi)始對(duì)heap中的對(duì)象進(jìn)行標(biāo)記,標(biāo)記線
    程與應(yīng)用程序線程并發(fā)執(zhí)行玖详,并且收集各個(gè)Region的存活對(duì)象信息把介。

  • 重新標(biāo)記( Remark, STW) :標(biāo)記那些在并發(fā)標(biāo)記階段發(fā)生變化的對(duì)象,將被回收蟋座。

  • 清理(Cleanup) :清除空Region (沒(méi)有存活對(duì)象的)拗踢,加入到free list。

  • 第一階段initial mark是共用了Young GC的暫停向臀,這是因?yàn)樗麄兛梢詮?fù)用rootscan操作巢墅,所以可以說(shuō)global concurrent marking是伴隨Young GC而發(fā)生的

  • 第四階段Cleanup只是回收了沒(méi)有存活對(duì)象的Region,所以它并不需要STW。

G1在運(yùn)行過(guò)程中的主要模式

  • YGC(不同于CMS)
    • G1 YGC在Eden充滿時(shí)觸發(fā)君纫,在回收之后所有之前屬于Eden的區(qū)塊全部變成空白驯遇,即不屬于任何一個(gè)分區(qū)( Eden、Survivor蓄髓、Old )
    • YGC執(zhí)行步驟:
      • 階段1:根掃描
        靜態(tài)和本地對(duì)象被描
      • 階段2:更新RS
        處理dirty card隊(duì)列更新RS
      • 階段3:處理RS
        檢測(cè)從年輕代指向老年代的對(duì)象
      • 階段4:對(duì)象拷貝
        拷貝存活的對(duì)象到survivor/old區(qū)域
      • 階段5:處理引用隊(duì)列
        軟引用叉庐,弱引用,虛引用處理
  • 并發(fā)階段(global concurrent marking)
  • 混合模式
  • Full GC (一 般是G1出現(xiàn)問(wèn)題時(shí)發(fā)生会喝,本質(zhì)上不屬于G1陡叠,G1進(jìn)行的回退策略(回退為:Serial Old GC))

什么時(shí)候發(fā)生MixedGC?

  • 由一些參數(shù)控制,另外也控制著哪些老年代Region會(huì)被選入CSet (收集集合)
    • G1HeapWastePercent:在globalconcurrent marking結(jié)束之后肢执,我們可以知道oldgenregions中有多少空間要被回收匾竿,在每次YGC之后和再次發(fā)生MixedGC之前,會(huì)檢查垃圾占比是否達(dá)到此參數(shù)蔚万,只有達(dá)到了岭妖,下次才 會(huì)發(fā)生Mixed GC
    • G1MixedGCLiveThresholdPercent: oldgeneration region中的存活對(duì)象的占比,只有在此參數(shù)之下反璃,才會(huì)被選入CSet
    • G1MixedGCCountTarget:一 次globalconcurrent marking之后昵慌,最多執(zhí)行Mixed GC的次數(shù)
    • G1OldCSetRegionThresholdPercent:次Mixed GC中能被選入CSet的最多old generation region數(shù)量

三色標(biāo)記算法

提到并發(fā)標(biāo)記,我們不得不了解并發(fā)標(biāo)記的三色標(biāo)記算法淮蜈。它是描述追蹤式回收器的一種有效的方法斋攀,利用它可以推演回收器的正確性

  • 我們將對(duì)象分成三種類(lèi)型:
    • 黑色:根對(duì)象,或者該對(duì)象與它的子對(duì)象都被掃描過(guò)(對(duì)象被標(biāo)記了梧田,且它的所有field也被標(biāo)記完了)
    • 灰色:對(duì)象本身被掃描,但還沒(méi)掃描完該對(duì)象中的子對(duì)象( 它的field還沒(méi)有被標(biāo)記或標(biāo)記完)
    • 白色:未被掃描對(duì)象淳蔼,掃描完成所有對(duì)象之后,最終為白色的為不可達(dá)對(duì)象裁眯,即垃圾對(duì)象(對(duì)象沒(méi)有被標(biāo)記到)

提到并發(fā)標(biāo)記鹉梨,我們不得不了解并發(fā)標(biāo)記的三色標(biāo)記算法。它是描述追蹤式回收器的一種有效的方法穿稳,利用它可以推演回收器的正確性

遍歷了所有可達(dá)的對(duì)象后存皂,所有可達(dá)的對(duì)象都變成了黑色。不可達(dá)的對(duì)象即為白色逢艘,需要被清理,如圖:

三色標(biāo)記算法
  • 但是如果在標(biāo)記過(guò)程中旦袋,應(yīng)用程序也在運(yùn)行,那么對(duì)象的指針就有可能改變它改。這樣的話疤孕,我們就會(huì)遇到一個(gè)問(wèn)題:對(duì)象丟失問(wèn)題

這時(shí)候應(yīng)用程序執(zhí)行了以下操作:
A.c=C
B.c=null
這樣,對(duì)象的狀態(tài)圖變成如下情形:

這時(shí)候垃圾收集器再標(biāo)記掃描的時(shí)候就會(huì)變成下圖這樣

  • 很顯然央拖,此時(shí)C是白色祭阀,被認(rèn)為是垃圾需要清理掉截亦,顯然這是不合理的

SATB

  • 在G1中,使用的是SATB ( Snapshot-At-The- Beginning)的方式柬讨,刪除的時(shí)候記錄所有的對(duì)象
  • 它有3個(gè)步驟
    • 在開(kāi)始標(biāo)記的時(shí)候生成一個(gè)快照?qǐng)D崩瓤,標(biāo)記存活對(duì)象
    • 在并發(fā)標(biāo)記的時(shí)候所有被改變的對(duì)象入隊(duì)(在writebarrier里把所有舊的引用所指向的對(duì)象都變成非白的)
    • 可能存在浮動(dòng)垃圾,將在下次被收集

G1混合式回收

  • G1到現(xiàn)在可以知道哪些老的分區(qū)可回收垃圾最多踩官。當(dāng)全局并發(fā)標(biāo)記完成后却桶,在某個(gè)時(shí)刻,就開(kāi)始了Mixed GC蔗牡。這些垃圾回收被稱(chēng)作“混合式”是因?yàn)樗麄儾粌H僅進(jìn)行正常的新生代垃圾收集颖系,同時(shí)也回收部分后臺(tái)掃描線程標(biāo)記的分區(qū)混合式GC也是采用的復(fù)制清理策略,當(dāng)GC完成后辩越,會(huì)重新釋放空間

SATB詳解

  • SATB是維持并發(fā)GC的一種手段嘁扼。G1并發(fā)的基礎(chǔ)就是SATB。SATB可以理解成在GC開(kāi)始之前對(duì)堆內(nèi)存里的對(duì)象做次快照黔攒,此時(shí)活的對(duì)象就認(rèn)為是活的趁啸,從而形成了一個(gè)對(duì)象圖。
  • 在GC收集的時(shí)候督惰,新生代的對(duì)象也認(rèn)為是活的對(duì)象不傅,除此之外其他不可達(dá)的對(duì)象都認(rèn)為是垃圾對(duì)象

如何找到在GC過(guò)程中分配的對(duì)象呢?

  • 每個(gè)region記錄著兩個(gè)top-at-mark-start ( TAMS 指針,分別為prevTAMS和nextTAMS赏胚。在TAMS以上的對(duì)象就是新分配的访娶,因而被視為隱式marked。

  • 通過(guò)這種方式我們就找到了在GC過(guò)程中新分配的對(duì)象觉阅,并把這些對(duì)象認(rèn)為是活的對(duì)象崖疤。

  • 解決了對(duì)象在GC過(guò)程中分配的問(wèn)題,那么在GC過(guò)程中引用發(fā)生變化的問(wèn)題怎么解決呢?

  • G1給出的解決辦法是通過(guò)WriteBarrier.Write Barrier就是對(duì)引用字段進(jìn)行賦值做了額外處理典勇。通過(guò)Write Barrier就可以了解到哪些引用對(duì)象發(fā)生了什么樣的變化

mark的過(guò)程就是遍歷heap標(biāo)記live object的過(guò)程劫哼,

  • 采用的是三色標(biāo)記算法,這三種顏色為white(表示還未訪問(wèn)到)痴柔、gray(訪問(wèn)到但是它用到的引用還沒(méi)有完全掃描沦偎、black( 訪問(wèn)到而且其用到的引用已經(jīng)完全掃描完)

  • 整個(gè)三色標(biāo)記算法就是從GCroots出發(fā)遍歷heap,針對(duì)可達(dá)對(duì)象先標(biāo)記white為gray,然后再標(biāo)記gray為black;遍歷完成之后所有可達(dá)對(duì)象都是black的疫向,所有white都是可以回收的

  • SATB僅僅對(duì)于在marking開(kāi)始階段進(jìn)行"snapshot"(marked all reachable at markstart)咳蔚,但是concurrent的時(shí)候并發(fā)修改可能造成對(duì)象漏標(biāo)記

  • 對(duì)black新引用了一個(gè)white對(duì)象,然后又從gray對(duì)象中刪除了對(duì)該white對(duì)象的引用搔驼,這樣會(huì)造成了該white對(duì)象漏標(biāo)記

  • 對(duì)black新引用了一個(gè)white對(duì)象谈火,然后從gray對(duì)象刪了一個(gè)引用該white對(duì)象的white對(duì)象,這樣也會(huì)造成了該white對(duì)象漏標(biāo)記舌涨,

  • 對(duì)black新引用了一個(gè)剛new出來(lái)的white對(duì)象,沒(méi)有其他gray對(duì)象引用該white對(duì)象,這樣也會(huì)造成了該white對(duì)象漏標(biāo)記

  • 對(duì)于三色算法在concurrent的時(shí)候可能產(chǎn)生的漏標(biāo)記問(wèn)題革为,SATB在marking階段中舵鳞,對(duì)于從gray對(duì)象移除的目標(biāo)引用對(duì)象標(biāo)記為gray,對(duì)于black引用的新產(chǎn)生的對(duì)象標(biāo)記為black;由于是在開(kāi)始的時(shí)候進(jìn)行snapshot,因而可能存在Floating Garbage

漏標(biāo)與誤標(biāo)

  • 誤標(biāo)沒(méi)什么關(guān)系震檩,頂多造成浮動(dòng)垃圾,在下次gc還是可以回收的蜓堕,但是漏標(biāo)的后果是致命的抛虏,把本應(yīng)該存活的對(duì)象給回收了,從而影響的程序的正確性

  • 漏標(biāo)的情況只會(huì)發(fā)生在白色對(duì)象中套才,且滿足以下任意一個(gè)條件

    • 并發(fā)標(biāo)記時(shí)迂猴,應(yīng)用線程給一個(gè)黑色對(duì)象的引用類(lèi)型字段賦值 了該白色對(duì)象

    • 并發(fā)標(biāo)記時(shí),應(yīng)用線程刪除所有灰色對(duì)象到該白色對(duì)象的引用

  • 對(duì)于第一種情況背伴,利用post-write barrier,記錄所有新增的引用關(guān)系沸毁,然后根據(jù)這些引用關(guān)系為根重新掃描一-遍

  • 對(duì)于第二種情況,利用pre-write barrier,將所有即將被刪除的引用關(guān)系的舊引用記錄下來(lái)傻寂,最后以這些舊引用為根重新掃描一遍

停頓預(yù)測(cè)模型

  • G1收集器突出表現(xiàn)出來(lái)的一點(diǎn)是通過(guò)一個(gè)停頓預(yù)測(cè)模型根據(jù)用戶配置的停頓時(shí)間來(lái)選擇CSet的大小以清,從而達(dá)到用戶期待的應(yīng)用程序暫停時(shí)間。

  • 通過(guò)-XX:MaxGCPauseMillis參數(shù)來(lái)設(shè)置崎逃。這一點(diǎn)有點(diǎn)類(lèi)似于ParallelScavenge收集器掷倔。 關(guān)于停頓時(shí)間的設(shè)置并不是越短越好。

  • 設(shè)置的時(shí)間越短意味著每次收集的CSet越小个绍,導(dǎo)致垃圾逐步積累變多勒葱,最終不得不退化成SerialGC;停頓時(shí)間設(shè)置的過(guò)長(zhǎng),那么會(huì)導(dǎo)致每次都會(huì)產(chǎn)生長(zhǎng)時(shí)間的停頓巴柿,影響了程序?qū)ν獾捻憫?yīng)時(shí)間

G1的收集模式

  • G1的運(yùn)行過(guò)程是這樣的:會(huì)在Young GC和Mixed GC之間不斷地切換運(yùn)行凛虽,同時(shí)定期地做全局并發(fā)標(biāo)記,在實(shí)在趕不上對(duì)象創(chuàng)建速度的情況下 使用Full GC(Serial GC)广恢。
  • 初始標(biāo)記是在Young GC.上執(zhí)行的凯旋,在進(jìn)行全局并發(fā)標(biāo)記的時(shí)候不會(huì)做MixedGC,在做MixedGC的時(shí)候也不會(huì)啟動(dòng)初始標(biāo)記階段。
  • 當(dāng)MixedGC趕不上對(duì)象產(chǎn)生的速度的時(shí)候就退化成FullGC钉迷,這一點(diǎn)是需要重點(diǎn)調(diào)優(yōu)的地方

G1最佳實(shí)踐

  • 不要設(shè)置新生代和老年代的大小,G1收集器在運(yùn)行的時(shí)候會(huì)調(diào)整新生代和老年代
    的大小荒椭。通過(guò)改變代的大小來(lái)調(diào)整對(duì)象晉升的速度以及晉升年齡趣惠,從而達(dá)到我們?yōu)槭占髟O(shè)置的暫停時(shí)間目標(biāo)草戈。

  • 設(shè)置了新生代大小相當(dāng)于放棄了G1為我們做的自動(dòng)調(diào)優(yōu)猾瘸。我們需要做的只是設(shè)置整個(gè)堆內(nèi)存的大小牵触,剩下的交給G1自已去分配各個(gè)代的大小即可揽思。

  • 不斷調(diào)優(yōu)暫停時(shí)間指標(biāo)

    • 通過(guò)-XX:MaxGCPauseMillis=x可以設(shè)置啟動(dòng)應(yīng)用程序暫停的時(shí)間,G1在運(yùn)行的時(shí)候會(huì)根據(jù)這個(gè)參數(shù)選擇CSet來(lái)滿足響應(yīng)時(shí)間的設(shè)置损痰。一般情況下這個(gè)值設(shè)置到100ms或者200ms都是可以的(不同情況下會(huì)不一樣)卢未,但如果設(shè)置成50ms就不太合理辽社。暫停時(shí)間設(shè)置的太短,就會(huì)導(dǎo)致出 現(xiàn)G1跟不上垃圾產(chǎn)生的速度汉匙。最終退化成Full GC噩翠。所以對(duì)這個(gè)參數(shù)的調(diào)優(yōu)是一個(gè)持續(xù)的過(guò)程绎秒,逐步調(diào)整到最佳狀態(tài)见芹。
  • 關(guān)注Evacuation Failure

    • Evacuation(表示copy) Failure類(lèi)似于CMS里面的晉升失敗,堆空間的垃圾太多導(dǎo)致無(wú)法完成Region之間的拷貝徘铝,于是不得不退化成Full GC來(lái)做一次全局范圍內(nèi)的垃圾收集

G1日志解析:


/**
 * 
 * G1日志分析
 * 虛擬機(jī)相關(guān)參數(shù):
 * -verbose:gc
 * -Xms10m
 * -Xmx10m
 * -XX:+UseG1GC 表示垃圾收集器使用G1
 * -XX:+PrintGCDetails
 * -XX:+PrintGCDateStamps
 * -XX:MaxGCPauseMillis=200m 設(shè)置垃圾收集最大停頓時(shí)間
 */
public class G1LogAnalysis {

    public static void main(String[] args) {
        int size = 1024 * 1024;
        byte[] bytes1 = new byte[size];
        byte[] bytes2 = new byte[size];
        byte[] bytes3 = new byte[size];
        byte[] bytes4 = new byte[size];
        System.out.println("hello world");
    }
}
/**
 * GC日志:
 * 2020-04-14T16:13:41.663+0800: [GC pause (G1 Humongous Allocation【說(shuō)明分配的對(duì)象超過(guò)了region大小的50%】) (young) (initial-mark), 0.0014516 secs]
 * [Parallel Time: 1.1 ms, GC Workers: 4【GC工作線程數(shù)】]
 * [GC Worker Start (ms): Min: 167.0, Avg: 167.1, Max: 167.1, Diff: 0.1]【幾個(gè)垃圾收集工作的相關(guān)信息統(tǒng)計(jì)】
 * [Ext Root Scanning (ms): Min: 0.4, Avg: 0.4, Max: 0.4, Diff: 0.1, Sum: 1.6]
 * [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 * [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
 * [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 * [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 * [Object Copy (ms): Min: 0.6, Avg: 0.6, Max: 0.6, Diff: 0.0, Sum: 2.4]
 * [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
 * [Termination Attempts: Min: 1, Avg: 1.3, Max: 2, Diff: 1, Sum: 5]
 * 【上面的幾個(gè)步驟為YOUNG GC的固定執(zhí)行步驟】
 * 階段1:根掃描
 * 靜態(tài)和本地對(duì)象被描
 * 階段2:更新RS
 * 處理dirty card隊(duì)列更新RS
 * 階段3:處理RS
 * 檢測(cè)從年輕代指向老年代的對(duì)象
 * 階段4:對(duì)象拷貝
 * 拷貝存活的對(duì)象到survivor/old區(qū)域
 * 階段5:處理引用隊(duì)列
 * 軟引用,弱引用淹魄,虛引用處理
 * [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.2]
 * [GC Worker Total (ms): Min: 1.0, Avg: 1.1, Max: 1.1, Diff: 0.1, Sum: 4.2]
 * [GC Worker End (ms): Min: 168.1, Avg: 168.1, Max: 168.1, Diff: 0.0]
 * [Code Root Fixup: 0.0 ms]
 * [Code Root Purge: 0.0 ms]
 * [Clear CT: 0.1 ms]【清楚cardTable所花費(fèi)時(shí)間】
 * [Other: 0.3 ms]
 * [Choose CSet: 0.0 ms]
 * [Ref Proc: 0.1 ms]
 * [Ref Enq: 0.0 ms]
 * [Redirty Cards: 0.1 ms]
 * [Humongous Register: 0.0 ms]
 * [Humongous Reclaim: 0.0 ms]
 * [Free CSet: 0.0 ms]
 * [Eden: 2048.0K(4096.0K)->0.0B【新生代清理后】(2048.0K) Survivors: 0.0B->1024.0K Heap: 3800.2K(10.0M)->2752.1K(10.0M)]
 * [Times: user=0.00 sys=0.00, real=0.01 secs]
 * 2020-04-14T16:13:41.671+0800: [GC concurrent-root-region-scan-start]
 * 2020-04-14T16:13:41.671+0800: [GC concurrent-root-region-scan-end, 0.0008592 secs]
 * 2020-04-14T16:13:41.671+0800: [GC concurrent-mark-start]
 * 2020-04-14T16:13:41.672+0800: [GC concurrent-mark-end, 0.0000795 secs]
 * 2020-04-14T16:13:41.672+0800: [GC remark 2020-04-14T16:13:41.672+0800: [Finalize Marking, 0.0001170 secs] 2020-04-14T16:13:41.672+0800: [GC ref-proc, 0.0002159 secs] 2020-04-14T16:13:41.672+0800: [Unloading, 0.0005800 secs], 0.0011024 secs]
 * [Times: user=0.00 sys=0.00, real=0.00 secs]
 * 2020-04-14T16:13:41.673+0800: [GC cleanup 4800K->4800K(10M), 0.0003239 secs]
 * [Times: user=0.00 sys=0.00, real=0.00 secs]
 * hello world
 * Heap
 * garbage-first heap   total 10240K, used 4800K [0x00000000ff600000, 0x00000000ff700050, 0x0000000100000000)
 * region size 1024K【說(shuō)明region默認(rèn)大小】, 2 young (2048K), 1 survivors (1024K)
 * Metaspace       used 3224K, capacity 4496K, committed 4864K, reserved 1056768K
 * class space    used 350K, capacity 388K, committed 512K, reserved 1048576K
 */
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羽戒,一起剝皮案震驚了整個(gè)濱河市缸废,隨后出現(xiàn)的幾起案子呆奕,更是在濱河造成了極大的恐慌梁钾,老刑警劉巖姆泻,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拇勃,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡蟀架,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)妓肢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)碉钠,“玉大人,你說(shuō)我怎么就攤上這事栗弟『嵬龋” “怎么了揪惦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵器腋,是天一觀的道長(zhǎng)纫塌。 經(jīng)常有香客問(wèn)我,道長(zhǎng)避除,這世上最難降的妖魔是什么瓶摆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任状飞,我火速辦了婚禮酵使,結(jié)果婚禮上凝化,老公的妹妹穿的比我還像新娘。我一直安慰自己混巧,他們只是感情好晰绎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布陨亡。 她就那樣靜靜地躺著,像睡著了一般蛙埂。 火紅的嫁衣襯著肌膚如雪遮糖。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天屡江,我揣著相機(jī)與錄音赛不,去河邊找鬼踢故。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臊诊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玷或,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蔬胯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼氛濒!你這毒婦竟也來(lái)了舞竿?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤执桌,失蹤者是張志新(化名)和其女友劉穎仰挣,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體香椎,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年玛界,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慎框。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笨枯。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡严嗜,死狀恐怖漫玄,靈堂內(nèi)的尸體忽然破棺而出睦优,到底是詐尸還是另有隱情刨秆,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布家凯,位于F島的核電站,受9級(jí)特大地震影響如失,放射性物質(zhì)發(fā)生泄漏绊诲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一褪贵、第九天 我趴在偏房一處隱蔽的房頂上張望掂之。 院中可真熱鬧,春花似錦脆丁、人聲如沸世舰。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)无切。三九已至籍嘹,卻和暖如春颂碘,著一層夾襖步出監(jiān)牢的瞬間峡竣,已是汗流浹背载城。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留河狐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓贵白,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剖踊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348