JVM系列【6】GC與調優1


JVM系列筆記目錄

  • 虛擬機的基礎概念
  • class文件結構
  • class文件加載過程
  • jvm內存模型
  • JVM常用指令
  • GC與調優

GC基礎知識

  • 什么是垃圾

​ 沒有任何引用指向的一個對象或多個對象(循環引用)

file

  • 如何找到垃圾

    • 引用計數(ReferenceCount),缺點:無法解決循環引用
    • 根可達算法(RootSearching),從根開始查找,找到對象是有用的,找不到的對象為垃圾。

file

什么是根? 注意結合上一篇博客 JVM系列【5】JVM常用指令-運行時數據區進行理解。

  1. 線程棧變量 JVM Stack、native method stack
  2. 靜態變量 static refercences in method area、Clazz
  3. 常量池 runtime cosntant pool
  4. JNI指針 c/c++ 指針
  • 常見的垃圾回收算法

    1. 標記清除(mark sweep)

    缺點:位置不連續,產生碎片,效率偏低(需要進行兩遍掃描)

    適用情況:算法相對簡單,適用於存活對象比較多的情況
    file

    1. 拷貝算法 (copying)

      說明:沒有碎片,浪費空間,復制移動對象,需要調整對象引用

      適用情況:適用於存活對象較少的情況 只掃描一次

      file

    2. 標記壓縮(mark compact)

      說明:沒有碎片,效率偏低(兩遍掃描,指針需要調整)

    file

  • JVM堆內存分代模型(用於分代垃圾回收算法)

    堆內存分代模型是部分垃圾回收器使用的模型,除Epsilon ZGC Shenandoah 之外的GC都使用邏輯分代模型,但是G1 是邏輯分代 物理不分代,除此之外都是邏輯分代 而且物理分代。

    file

    分代模型中,分新生代和老年代,比例是1:2

    1. 新生代 = Eden區+ 2個survivor區

      YGC回收后,大多數的對象會被回收,活着的進入s0;

      再次YGC,活着的對象eden+s0 進入s1;

      再次YGC,活着的對象eden+s1 進入s0;

      年齡足夠進入老年代,一般垃圾回收器是15,CMS是6;為什么一般垃圾回收器分代年齡是15?參考下 JVM系列【4】內存模型-對象頭的內容有哪些,對象頭中4位標識GC年齡,所以最大的年齡是2^4 -1 = 15

      s 區裝不下,直接進入老年代。

    2. 老年代: 存放一些"頑固對象",老年代滿了或是分配不下了會觸發FCG。

    3. 永久代(Permanent Generation,JDK1.7以前)/元數據區(MetaSpace,JDK1.8以后):存放的是Class文件結構,永久代必須指定大小限制 ,元數據可以設置也可以不設置,無上限(受限於物理內存),字符串常量在1.7以前存放在永久代,1.8以后存放在堆中。

  • 垃圾回收類型和對象分配過程

    1. 垃圾回收類型

      上一個點解釋了堆內存分代模型,這里統一下概念:MinorGC=YGC指的是新生代即Y區的垃圾回收,MajorGC=FGC指的是老年代分配不下或是滿了發生的GC,包括新生代和老年代。

    2. 對象如何分配

      在之前的博客中 JVM系列【4】內存模型-new Object()面試6連問-對象如何分配,簡單提過這一點。

file

​ 對照流程圖,分配過程:

	> 1. new對象后優先在棧上分配,棧上分配的對象`pop`后就消失;
	> 2. 是否是大對象(Y區分配不下的對象)?是就分配到O區,O區發生FGC后回收
	> 3. 不是大對象,優先分配TLAB(Thread Local Allocation Buffer線程本地分配緩存)上,分配不下就分配到Eden區 。
  1. 了解棧上分配、TLAB、分配擔保機制和升代

    1. 哪些對象棧上分配?

      線程私有對象 、無逃逸對象即離開代碼塊就沒有引用的對象、支持標量替換的對象,如類中變量可以用基本變量替換。

    2. 線程本地分配Thread Local Allocation Buffer
      獨占eden空間,默認1%;多線程時候不用競爭eden就可以申請空間,提高效率;可分配小對象

    3. 分配擔保機制

      在新生代無法分配內存的時候,把新生代的對象轉移到老生代,然后把新對象放入騰空的新生代。參考

    4. 對象何時進入老年代?

      超過MaxTenuringThreshold指定的次數;

      根據動態年齡計算進入老年代,Survivor空間中年齡從小到大的對象進行累加,當加入某個年齡段后,累加和超過survivor區域*TargetSurvivorRatio(默認50%)的時候,就從這個年齡段往上的年齡的對象進行晉升到老年代。參考

  • 常見的垃圾回收器

    常見的垃圾回收器有Serial/SerialOld、ParallelScavenge/ParallelOld、ParNew/CMS、G1、ZGC、Shenandoah、Epsilon。Serial/SerialOld、ParallelScavenge/ParallelOld、ParNew/CMS是分代的垃圾回收器,G1是邏輯上分代物理上不分代,ZGC和Shenandoah是不分代,Epsilon是JDK調試用的垃圾回收器。

    歷史:JDK誕生,Serial追隨,為了提供效率誕生PS,為配合CMS,誕生PN,CMS是1.4后期引入的,CMS是里程碑式的GC,但是CMS毛病比較多,因此目前沒有任何一個JDK版本默認CMS。

file

  • Serial

    年輕代 串行回收

    file

  • SerialOld

    老年代 串行回收

    file

  • PS(ParallelScavenge)

    年輕代 並行回收

    file

  • PO(ParallelOld)

    老年代 並行回收

    file

  • PN(ParNew)

    年輕代 增強版PS配合CMS的並行回收。PN 和 PS區別?PN 響應時間優先;PS吞吐量優先

  • CMS(ConcurrentMarkSweep)

    老年代並發的,垃圾回收和應用程序同時運行,降低STW的時間(200ms);

    CMS問題比較多,所以現在沒有一個版本默認是CMS,只能手工指定;

    CMS既然是MarkSweep,就一定會有碎片化的問題,碎片到達一定程度,CMS的老年代分配對象分配不下的時候,使用SerialOld 進行老年代回收,STW無法忍受;

    • 如何解決碎片化:設定-XX:+UseCMSCompactAtFullCollection 默認開啟;設定-XX:CMSFullGCsBeforeCompaction,默認為0 指經過多少次FGC才進行壓縮。
    • 浮動垃圾問題解決?降低觸發CMS的閾值,保持老年代有足夠的空間;參數-XX:CMSInitiatingOccupancyFraction 指定使用CMS時老年代使用了指定閾值的內存后觸發FGC,建議68-92%

    使用的算法:三色標記+Increamental Update

  • G1

    STW可以達到10ms

    算法:三色標記+SATB

  • ZGC

    STW號稱可以達到1ms

    算法:顏色指針ColoredPointers + LoadBarrier

  • Shenandaoh

    算法:ColoredPointers + WriteBarrier

  • 垃圾回收器和內存大小的關系

    Serial 幾十兆

    PS 上百兆-幾個G

    CMS 20G左右

    G1 上百G

    ZGC 4T-16T(JDK13可以支持)

知識分享,轉載請注明出處。學無先后,達者為先!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM