垃圾收集器與記憶體分配策略

来源:https://www.cnblogs.com/xtt321/archive/2022/05/02/16215372.html
-Advertisement-
Play Games

程式計數器、虛擬機棧、本地方法棧三個區域隨著線程的創建而創建、執行完成銷毀,棧中的棧幀隨著放大的進入和退出執行入棧與出棧,每個棧幀分配多少記憶體基本上是在類結構確定下來時已知,因此這幾個區域的記憶體分配與回收都具備確定性。Java堆中存放的所有對象的實例,只有在程式運行期間我們才會知道會創建哪些對象,這 ...


程式計數器、虛擬機棧、本地方法棧三個區域隨著線程的創建而創建、執行完成銷毀,棧中的棧幀隨著放大的進入和退出執行入棧與出棧,每個棧幀分配多少記憶體基本上是在類結構確定下來時已知,因此這幾個區域的記憶體分配與回收都具備確定性。
Java堆中存放的所有對象的實例,只有在程式運行期間我們才會知道會創建哪些對象,這部分記憶體分配與回收都是動態的,垃圾收集器重點關註的就是這部分。

引入計數算數
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器都為0的的對象就是不可能再被使用的。
缺點:它很難解決對象之間的相互迴圈引用的問題。

VM ages:-XX:+PrintGCDetails 列印GC詳細信息:

package memory;

public class ReferenceCountingGC {

    public Object instance = null;

    private static  final  int _1MB = 1024 *1024;

    private byte[] bigSize = new byte[2 *_1MB];

    public static  void  main(String[] arg){
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;

        System.gc();
    }
}

日誌:

[15.841s][info   ][gc,start    ] GC(0) Pause Full (System.gc())
[15.842s][info   ][gc,task     ] GC(0) Using 3 workers of 8 for full compaction
[15.843s][info   ][gc,phases,start] GC(0) Phase 1: Mark live objects
[15.847s][info   ][gc,phases      ] GC(0) Phase 1: Mark live objects 4.412ms
[15.848s][info   ][gc,phases,start] GC(0) Phase 2: Prepare for compaction
[15.849s][info   ][gc,phases      ] GC(0) Phase 2: Prepare for compaction 1.244ms
[15.849s][info   ][gc,phases,start] GC(0) Phase 3: Adjust pointers
[15.851s][info   ][gc,phases      ] GC(0) Phase 3: Adjust pointers 1.951ms
[15.851s][info   ][gc,phases,start] GC(0) Phase 4: Compact heap
[15.853s][info   ][gc,phases      ] GC(0) Phase 4: Compact heap 1.987ms
[15.857s][info   ][gc,heap        ] GC(0) Eden regions: 4->0(9)
[15.857s][info   ][gc,heap        ] GC(0) Survivor regions: 0->0(0)
[15.857s][info   ][gc,heap        ] GC(0) Old regions: 0->3
[15.857s][info   ][gc,heap        ] GC(0) Archive regions: 0->0
[15.857s][info   ][gc,heap        ] GC(0) Humongous regions: 6->6
[15.857s][info   ][gc,metaspace   ] GC(0) Metaspace: 424K(640K)->424K(640K) NonClass: 399K(512K)->399K(512K) Class: 24K(128K)->24K(128K)
[15.857s][info   ][gc             ] GC(0) Pause Full (System.gc()) 9M->6M(30M) 15.980ms
[15.857s][info   ][gc,cpu         ] GC(0) User=0.02s Sys=0.02s Real=0.02s
[17.684s][info   ][gc,heap,exit   ] Heap
[17.684s][info   ][gc,heap,exit   ]  garbage-first heap   total 30720K, used 7088K [0x0000000081800000, 0x0000000100000000)
[17.684s][info   ][gc,heap,exit   ]   region size 1024K, 1 young (1024K), 0 survivors (0K)
[17.684s][info   ][gc,heap,exit   ]  Metaspace       used 425K, committed 640K, reserved 1114112K
[17.684s][info   ][gc,heap,exit   ]   class space    used 24K, committed 128K, reserved 1048576K

從日誌看出,記憶體進行了回收,說明JVM 的GC使用的不是引用計數演算法。

根搜索演算法
通過一系列的名為 “GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象的GC Roots 沒有任何引用鏈相連時,則證明此對象是不可用的。

引用
引用分為:

  • 強引用(Strong Reference) :只要強引用還在,垃圾收集器永遠不會回收掉引用的對象。
  • 軟引用(Soft Reference):在系統將要發生記憶體溢出異常之前,將會把這些對象列進回收範圍之中併進行第二次回收。如果這次回收還沒有足夠的記憶體,才會拋出記憶體溢出異常。
  • 弱引用(Weak Reference):被弱引用關聯的對象只能生存到下一次垃圾收集發生之前。當垃圾收集器工作時,無論當前記憶體是否足夠,都會回收掉只被弱引用關聯的對象。
  • 虛引用(Phantom Reference)(幽靈引用、幻影引用):一個對象是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象實例。為一個對象設置虛引用關聯的唯一目的就是希望能在這個對象被收集器回收時收到一個系統通知。

在跟搜索演算法中不可達的對象,至少要經歷兩次標記過程:如果對象在進行根搜索後發現沒有與GC Roots相連的引用鏈,那它將會被第一次標記併進行一次篩選,篩選條件是此對象是否有必要執行finalize()方法。當對象沒有覆蓋finalize()方法,或者finalize()方法已經被虛擬機調用過,虛擬機將這兩種情況視為“沒有必要執行”。
如果對象有必要執行finalize()方法,那麼這個對象將被放置在一個F-Queue的隊列之中由Finalizer線程(虛擬機建立並出發)執行。finalizer用於告訴垃圾回收器下一步應該執行的操作。然後,GC將對F-Queue中的對象進行二次小規模的標記。

package memory;

public class FinalizeEscapeGC {

    public static  FinalizeEscapeGC SAVE_HOOK = null;

    public  void  isAlive(){
        System.out.println("yes, i am still alive;");
    }
    @Override
    protected void finalize() throws Throwable{
        super.finalize();
        System.out.println("fialize mehtod executed!");
        //重新引用
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable{
        SAVE_HOOK = new FinalizeEscapeGC();
        //對象第一次成功拯救自己
        SAVE_HOOK = null;
        System.gc();
        //因為Finalizer方法優先順序很低,暫停500毫秒,等它執行
        Thread.sleep(500);

        if(SAVE_HOOK != null){
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no ,i am dead");
        }
        //下麵這段代碼與上面的完全相同,但是這次自救失敗~
        SAVE_HOOK = null;

        System.gc();

        Thread.sleep(500);

        if(SAVE_HOOK != null){
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no ,i am dead !!!");
        }
    }
}

運行結果:

fialize mehtod executed!
yes, i am still alive;
no ,i am dead !!!

任何一個對象的finalize()方法都只會被系統自動調用一次,如果對象面臨下一次回收,他的finalize()方法不會被再次執行。
finalize()能做的所有工作,使用try-finally或者其他方式都可以做得更好、更及時。

回收方法區

  • 回收的主要內容為:廢棄常量和無用的類
  • 廢棄常量:沒有任何對象引用常量池中的常量,也沒有其他地方引用這個字面量。
  • 無用類判定條件:
  1. 該類所有的實例都已經被回收,也就是Java堆中不存在該類的任何實例。
  2. 載入該類的ClassLoader已經被回收。
  3. 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

垃圾收集演算法


標記-清除演算法
首先標記出所有需要回收的對象,在標記完成後同意回收掉所有被標記的對象。
缺點:

  • 一個是效率問題,標記和清除過程的效率都不高;
  • 另一個是空間問題,標記清除之後會產生大量不連續的記憶體碎片,空間碎片太多可能會導致程式在需要分配較大對象時無法找到連續的記憶體,而不得不提前觸發另一次垃圾收集動作。

複製演算法
將可用記憶體按容量劃分為大小相等的兩塊,每次只使用其中的一塊,當這一塊記憶體用完後,就將還存活的對象複製到另外一塊上面,然後再把已使用過的記憶體空間一次清理掉。
缺點:將記憶體縮小為原來的一半。
現在商業虛擬機都採用這種收機演算法來回收新生代,將記憶體分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中的一塊Survivor。當回收時,將Eden和Survivor中還存活的對象一次性拷貝到另外一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor空間。
這裡有個問題,無法保證回收後存活對象一塊Survivor空間夠用,所以這裡需要依賴其他記憶體(老年代)進行分配擔保。

標記-整理演算法
根據老年代的特點,對存活對象進行標記,讓所有存活對象向一端移動,然後直接清理掉端邊以外的記憶體。

分代收機演算法
根據對象噸貨周期的不同將記憶體劃分為幾塊,JAVA一般將堆分為新生代和老生代,這樣就可以根據各個年代的特點採用最適當的收集演算法。

垃圾收集器
Serial收集器
是最基本、歷史最悠久的收集器,是一個單線程收集器,在進行垃圾收集的時候,會暫停掉其他的所有工作線程。(簡單而高效)

ParNew收集器
Serial收集器的多線程版,除了使用多線程進行垃圾收集外,其餘的與Serial收集器一致。關註點是儘可能縮短用戶線程停頓時間。

Parallel Scavenge 收集器
新生代收集器,他也是使用複製演算法的收集器,也是並行的多線程收集器。目標是達到一個可控制的吞吐量。自適應調節策略。
吞吐量 = 運行用戶代碼的時間/(運行用戶代碼時間+垃圾收集時間)
停頓時間越短就越需要與用戶交互的程式,良好的響應速度能提升用戶體驗;高吞吐量則可以更高效率地利用CPU時間,儘快完成程式的運算任務,主要適用於後臺運算而不需要太多交互的任務。

Serial Old收集器
Serial Old是Serial收集器的老年代版本,使用“標記-整理”演算法。

Parallel Old收集器
是Parallel Scavenge收集器的老年代版本,使用多線程和“標記-整理”演算法。

CMS收集器
CMS收集器是一種以獲取最短回收停頓時間為目標的收集器。使用“標記-清除”演算法實現。
步驟:

  • 初始標記
  • 併發標記
  • 重新標記
  • 併發清除
  • 其中初始標記、重新標記兩個步驟需要用戶工作線程暫停,初始標記只標記GC Roots能直接關聯到的對象,併發標記階段進行 GC Root Tracing 過程,重新標記階段則是為修正併發標記期間,用戶程式繼續運行而導致標記變化產生變動的那部分對象的標記記錄。
  • 缺點:
  • CMS收集器對CPU資源非常敏感。CMS預設用的回收線程數(CPU數量+3)/4。為解決該問題,虛擬機提供了一種i-CMS(增量式併發收集器)的CMS收集器變種,工作方式就是在併發標記和併發清理的時候讓GC線程與用戶線程交替運行,儘量減少GC線程獨占資源的時間,這樣整個垃圾收集的過程會更長,但對用戶程式的影響就會顯得少一些。
  • CMS收集器無法處理浮動垃圾。如果CMS運行期預留的記憶體無法滿足程式需要,就會出現一次“Concurrent Mode Failure”失敗,這時候虛擬機將啟動後備元:臨時啟動Serial Old 收集器重新進行老年代的垃圾收集。
  • CMS是一款基於“標記-清除”演算法實現的收集器,收集結束時會產生大量的空間碎片。

G1 收集器

  • G1收集器是基於“標記-整理”演算法實現的收集器,也就是說它不會產生空間碎片,這對於長時間運行的應用系統來說非常重要。
  • 它可以非常精準地控制停頓,既能讓使用者明確指定在一個長度為M毫秒的時間片段,消耗在垃圾收集上的時間不得超過N毫秒。

G1將正好Java堆(包括新生代、老年代)劃分為多個大小固定的獨立區域,並且跟蹤這些區域裡面的垃圾堆積程度,在後臺維護一個優先列表,每次根據允許的收集時間,有限回抽垃圾最多的區域。

記憶體分配和回收策略

對象優先在Eden分配

多數情況下,對象在新生代Eden區中扽配,當Eden區域沒有足夠的空間分配時,虛擬機將發起一次Minor GC。

package memory;

public class JavaEdenTest {

    private static  final  int _1MB = 1024 *1024;

    public  static  void  testAllocation(){
        byte[] allocation1,allocation2,allocation3,allocation4;
        allocation1 = new byte[2 *_1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new  byte[2 *_1MB];
        allocation4 = new  byte[4 *_1MB];
    }

    /**
     * -verbose:gc
     * -Xms20M -Xmx20M -Xmn10M   顯示JAVA堆的大小20M且不可擴展
     * 其中10M分配給新生代,剩餘10M分配給老年代
     * -XX:SurvivorRatio=8 確定新生代中的Eden區與一個Survivor區域的空間比例為8:1
     * -XX:+PrintGCDetails 列印詳細的收集器日誌參數
     *
     * @param args
     */
    public  static  void  main(String[] args){
        testAllocation();
    }
}

運行日誌:

[16.630s][info   ][gc,start    ] GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation)
[16.631s][info   ][gc,task     ] GC(0) Using 2 workers of 8 for evacuation
[16.639s][info   ][gc,phases   ] GC(0)   Pre Evacuate Collection Set: 0.3ms
[16.639s][info   ][gc,phases   ] GC(0)   Merge Heap Roots: 0.1ms
[16.639s][info   ][gc,phases   ] GC(0)   Evacuate Collection Set: 4.8ms
[16.639s][info   ][gc,phases   ] GC(0)   Post Evacuate Collection Set: 2.1ms
[16.639s][info   ][gc,phases   ] GC(0)   Other: 0.8ms
[16.639s][info   ][gc,heap     ] GC(0) Eden regions: 3->0(9)
[16.639s][info   ][gc,heap     ] GC(0) Survivor regions: 0->1(2)
[16.639s][info   ][gc,heap     ] GC(0) Old regions: 0->0
[16.639s][info   ][gc,heap     ] GC(0) Archive regions: 0->0
[16.639s][info   ][gc,heap     ] GC(0) Humongous regions: 9->9
[16.639s][info   ][gc,metaspace] GC(0) Metaspace: 419K(576K)->419K(576K) NonClass: 394K(448K)->394K(448K) Class: 24K(128K)->24K(128K)
[16.639s][info   ][gc          ] GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 11M->10M(20M) 9.150ms
[16.639s][info   ][gc,cpu      ] GC(0) User=0.00s Sys=0.00s Real=0.01s
[16.640s][info   ][gc          ] GC(1) Concurrent Undo Cycle
[16.640s][info   ][gc,marking  ] GC(1) Concurrent Cleanup for Next Mark
[16.640s][info   ][gc,marking  ] GC(1) Concurrent Cleanup for Next Mark 0.402ms
[16.640s][info   ][gc          ] GC(1) Concurrent Undo Cycle 0.770ms

allocation4在實例化時,出發了一次Minor GC。

大對象直接進入老年代
VM參數:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:PretenureSizeThreshold=3145728
-XX:PretenureSizeThreshold的作用是令大於這個設置值的對象直接進入老年代中分配。
避免在Eden區及兩個Survivor區之間發生大量的記憶體拷貝。

package memory;

public class JavaTestBigObjectGC {

    private static  final int _1MB = 1024 * 1024;

    public  static  void  main(String[] args){
        byte[] allocation;
        allocation = new byte[4 * _1MB];
    }
}

運行日誌:

[5.942s][info   ][gc,heap,exit] Heap
[5.942s][info   ][gc,heap,exit]  garbage-first heap   total 20480K, used 7586K [0x00000000fec00000, 0x0000000100000000)
[5.942s][info   ][gc,heap,exit]   region size 1024K, 3 young (3072K), 0 survivors (0K)
[5.942s][info   ][gc,heap,exit]  Metaspace       used 419K, committed 576K, reserved 1114112K
[5.942s][info   ][gc,heap,exit]   class space    used 24K, committed 128K, reserved 1048576K

長期存活對象進入老年代
虛擬機給每個對象定義了一個對象年齡計數器,如果對象在Eden中生成,沒經過一次Minor GC後仍然存活,並且能被Survivor容納的話,將會被移動到Survivor空間中,並將對象年齡設置為1,當年齡增加到一定程度(預設為15歲)時,就會被晉升到老年代中。
對象寄生老年的年齡閾值,可以使用-XX:MaxTenuringThreshold來設置。

package memory;

public class JavaTestTenuringThreshold {

    private static  final int _1MB = 1024 *1024;

    /**
     * -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
     * -XX:MaxTenuringThreshold=1
     */
    public  static  void  testTenuringThreshold(){
        byte[] allocation1,allocation2,allocation3;
        allocation1 = new byte[4 * _1MB];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4* _1MB];
        allocation3 = null;
        allocation3 = new byte[4*_1MB];

    }

    public  static  void  main(String[] args){
        testTenuringThreshold();
    }
}
[6.680s][info   ][gc,start    ] GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation)
[6.680s][info   ][gc,task     ] GC(0) Using 2 workers of 8 for evacuation
[6.688s][info   ][gc,phases   ] GC(0)   Pre Evacuate Collection Set: 0.4ms
[6.688s][info   ][gc,phases   ] GC(0)   Merge Heap Roots: 0.2ms
[6.688s][info   ][gc,phases   ] GC(0)   Evacuate Collection Set: 4.8ms
[6.688s][info   ][gc,phases   ] GC(0)   Post Evacuate Collection Set: 1.8ms
[6.688s][info   ][gc,phases   ] GC(0)   Other: 0.7ms
[6.688s][info   ][gc,heap     ] GC(0) Eden regions: 3->0(9)
[6.688s][info   ][gc,heap     ] GC(0) Survivor regions: 0->1(2)
[6.688s][info   ][gc,heap     ] GC(0) Old regions: 0->0
[6.688s][info   ][gc,heap     ] GC(0) Archive regions: 0->0
[6.688s][info   ][gc,heap     ] GC(0) Humongous regions: 5->5
[6.688s][info   ][gc,metaspace] GC(0) Metaspace: 423K(640K)->423K(640K) NonClass: 399K(512K)->399K(512K) Class: 24K(128K)->24K(128K)
[6.688s][info   ][gc          ] GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 7M->6M(20M) 8.803ms
[6.688s][info   ][gc,cpu      ] GC(0) User=0.02s Sys=0.02s Real=0.01s
[6.689s][info   ][gc          ] GC(1) Concurrent Undo Cycle
[6.689s][info   ][gc,marking  ] GC(1) Concurrent Cleanup for Next Mark
[6.689s][info   ][gc,marking  ] GC(1) Concurrent Cleanup for Next Mark 0.187ms
[6.689s][info   ][gc          ] GC(1) Concurrent Undo Cycle 0.494ms
[6.696s][info   ][gc,start    ] GC(2) Pause Young (Concurrent Start) (G1 Humongous Allocation)
[6.696s][info   ][gc,task     ] GC(2) Using 2 workers of 8 for evacuation
[6.699s][info   ][gc,phases   ] GC(2)   Pre Evacuate Collection Set: 0.2ms
[6.699s][info   ][gc,phases   ] GC(2)   Merge Heap Roots: 0.1ms
[6.699s][info   ][gc,phases   ] GC(2)   Evacuate Collection Set: 1.9ms
[6.699s][info   ][gc,phases   ] GC(2)   Post Evacuate Collection Set: 0.5ms
[6.699s][info   ][gc,phases   ] GC(2)   Other: 0.1ms
[6.699s][info   ][gc,heap     ] GC(2) Eden regions: 0->0(10)
[6.699s][info   ][gc,heap     ] GC(2) Survivor regions: 1->0(2)
[6.699s][info   ][gc,heap     ] GC(2) Old regions: 0->1
[6.699s][info   ][gc,heap     ] GC(2) Archive regions: 0->0
[6.699s][info   ][gc,heap     ] GC(2) Humongous regions: 10->10
[6.699s][info   ][gc,metaspace] GC(2) Metaspace: 424K(640K)->424K(640K) NonClass: 399K(512K)->399K(512K) Class: 24K(128K)->24K(128K)
[6.699s][info   ][gc          ] GC(2) Pause Young (Concurrent Start) (G1 Humongous Allocation) 11M->10M(20M) 3.165ms
[6.699s][info   ][gc,cpu      ] GC(2) User=0.02s Sys=0.02s Real=0.00s
[6.699s][info   ][gc          ] GC(3) Concurrent Mark Cycle
[6.699s][info   ][gc,marking  ] GC(3) Concurrent Clear Claimed Marks
[6.699s][info   ][gc,marking  ] GC(3) Concurrent Clear Claimed Marks 0.011ms
[6.699s][info   ][gc,marking  ] GC(3) Concurrent Scan Root Regions
[6.700s][info   ][gc,marking  ] GC(3) Concurrent Scan Root Regions 0.900ms
[6.700s][info   ][gc,marking  ] GC(3) Concurrent Mark
[6.700s][info   ][gc,marking  ] GC(3) Concurrent Mark From Roots
[6.700s][info   ][gc,task     ] GC(3) Using 2 workers of 2 for marking
[6.701s][info   ][gc,marking  ] GC(3) Concurrent Mark From Roots 0.666ms
[6.701s][info   ][gc,marking  ] GC(3) Concurrent Preclean
[6.701s][info   ][gc,marking  ] GC(3) Concurrent Preclean 0.013ms
[6.715s][info   ][gc,start    ] GC(3) Pause Remark
[6.716s][info   ][gc          ] GC(3) Pause Remark 15M->15M(20M) 0.810ms
[6.716s][info   ][gc,cpu      ] GC(3) User=0.00s Sys=0.00s Real=0.00s
[6.716s][info   ][gc,marking  ] GC(3) Concurrent Mark 16.267ms
[6.716s][info   ][gc,marking  ] GC(3) Concurrent Rebuild Remembered Sets
[6.716s][info   ][gc,marking  ] GC(3) Concurrent Rebuild Remembered Sets 0.007ms
[6.717s][info   ][gc,start    ] GC(3) Pause Cleanup
[6.717s][info   ][gc          ] GC(3) Pause Cleanup 15M->15M(20M) 0.019ms
[6.717s][info   ][gc,cpu      ] GC(3) User=0.00s Sys=0.00s Real=0.00s
[6.717s][info   ][gc,marking  ] GC(3) Concurrent Cleanup for Next Mark
[6.717s][info   ][gc,start    ] GC(4) Pause Young (Normal) (G1 Humongous Allocation)
[6.717s][info   ][gc,task     ] GC(4) Using 2 workers of 8 for evacuation
[6.718s][info   ][gc,phases   ] GC(4)   Pre Evacuate Collection Set: 0.1ms
[6.718s][info   ][gc,phases   ] GC(4)   Merge Heap Roots: 0.1ms
[6.718s][info   ][gc,phases   ] GC(4)   Evacuate Collection Set: 0.1ms
[6.718s][info   ][gc,phases   ] GC(4)   Post Evacuate Collection Set: 0.4ms
[6.718s][info   ][gc,phases   ] GC(4)   Other: 0.0ms
[6.718s][info   ][gc,heap     ] GC(4) Eden regions: 0->0(10)
[6.718s][info   ][gc,heap     ] GC(4) Survivor regions: 0->0(2)
[6.718s][info   ][gc,heap     ] GC(4) Old regions: 1->1
[6.718s][info   ][gc,heap     ] GC(4) Archive regions: 0->0
[6.718s][info   ][gc,heap     ] GC(4) Humongous regions: 15->10
[6.718s][info   ][gc,metaspace] GC(4) Metaspace: 424K(640K)->424K(640K) NonClass: 399K(512K)->399K(512K) Class: 24K(128K)->24K(128K)
[6.718s][info   ][gc          ] GC(4) Pause Young (Normal) (G1 Humongous Allocation) 15M->10M(20M) 0.861ms
[6.718s][info   ][gc,cpu      ] GC(4) User=0.00s Sys=0.00s Real=0.00s
[6.718s][info   ][gc,marking  ] GC(3) Concurrent Cleanup for Next Mark 1.440ms
[6.718s][info   ][gc          ] GC(3) Concurrent Mark Cycle 19.012ms

動態對象年齡判定
為了能更好地適應不同程式的記憶體情況,虛擬機並不總是要求對象的年齡必須達到MaxTenuringshold才能晉升老年代,如果在Survivor空間中相同年齡所有對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就可以直接進入老年代。

空間擔保
在發生Minor GC時,虛擬機會在檢測之前每次晉升到老年代的平均大小是否大於老年代的剩餘空間大小,如果大於,則改為直接進行一次Full GC。如果小於,則查看HandlePromotionFailure設置是否允許擔保失敗;如果允許,那隻會進行Minor GC;如果不允許,則也要改為進行一次 Full GC。


 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、序 工欲善其事,必先利其器。作為一名資深程式員,相信必有一款調試神器相伴左右,幫助你快速發現問題,解決問題。作為前端開發,我還很年輕,也喜歡去搗鼓一些東西,藉著文章的標題,先提一個問題:大家目前是怎麼調試前端?哈哈,我也大膽的猜測下,可能有這麼幾種: 不調試,直接看代碼找問題 console.l ...
  • 1.常用的命令 mkdir 文件夾名 創建文件夾 clear 清楚屏幕 ls或者ll 將當前目錄下的子文件和子目錄平鋪在控制台 find 目錄名 將對應目錄下的子孫文件或子孫目錄平鋪在控制台 rm 文件名 刪除文件 mv 源文件 重命名文件 cat ... 查看對應文件內容 2.git高級命令 gi ...
  • 前言 所謂軟體過程模型就是一種開發策略,這種策略針對軟體工程的各個階段提供了一套範形,使工程的進展達到預期的目的。對一個軟體的開發無論其大小,我們都需要選擇一個合適的軟體過程模型,這種選擇基於項目和應用的性質、採用的方法、需要的控制,以及要交付的產品的特點。一個錯誤模型的選擇,將迷失我們的開發方向。 ...
  • package com.oop.demo03;public class Pet { String name; int age; public void shout(){ System.out.println("叫了一聲"); }} package com.oop.demo03;import com. ...
  • 模板(不深挖哦,是最最淺的) 基本概念 模板就是建立通用的模具,大大提高復用性(類型參數化) 模板不能直接使用,它是一個框架 模板的通用不是萬能的 函數模板 C++另一種編程思想為泛型編程,主要是利用模板技術 語法 template<typename T> //聲明模板<typename 數據類型名 ...
  • 一、前言&背景 1、項目原因需要在windows系統搭建jenkins打包部署java項目(旋了一瓶二鍋頭也沒想明白為什麼要用windows部署項目) 2、這篇文章包含打包後創建tag用於版本回滾、通過SSH推送到遠程win10部署操作 3、本次用的是打jar包方式 4、既然分給我了就硬著頭皮上吧, ...
  • 選擇排序 非穩定版本與穩定版本 排序過程中選擇一個比較大(大到小排序)的數,然後把它放到數組中指定的位置;這時候可以直接與數組中指定位置交換數據,但是可能會導致同值的數據的順序發生改變,這就是所謂的“不穩定”。可以通過下圖來理解所謂的“穩定”和“非穩定”。 不穩定排序演算法按數字排序時,會打亂原本同值 ...
  • Springboot 整合 MyBatisPlus[詳細過程] 提要 這裡已經將Springboot環境創建好 這裡只是整合MyBatis過程 引入Maven依賴 添加MyBatisPlus啟動依賴,添加mysql-connector-java依賴 <!-- mybatis-plus --> <de ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...