### G1垃圾回收的過程
**dirty card queue:對于應用程序的引用賦值,如object1.field = object2,JVM會在之前和之后執行特殊的操作以在dirty card queue中入隊一個保存了對象引用信息的card,在年輕代回收的時候,G1會對dirty card queue中所有card進行處理,以更新RSet,保證RSet實時準確的反應引用關系。****為什么不在賦值的時候直接更新RSet呢?這是為了不損失性能,RSet的處理需要線程同步,開銷大,使用隊列可以一定程度上緩解同步操作RSet帶來的性能損失。**
* 年輕代GC
* **并行的、獨占式的(STW發生)的垃圾回收**,可能會發生對象的代晉升,將會把對象放入Survivor或者是老年代。
* 當Eden區內存空間耗盡的時候,G1會啟動一次年輕代垃圾回收,順帶回收Survivor區。
* G1 Young GC的時候,首先停止程序線程(STW),G1創建回收集(Collection set,需要被回收的內存分段集合,包括Eden區和Survivor區的所有內存分段)
* 第一階段:掃描根(GC Roots),GC Roots聯通RSet記錄的外部引用作為掃描存活對象的入口。
* 第二階段:處理**dirty card queue**中的card,更新RSet。此階段完成后,**RSet可以準確的反應老年代對所在的內存分段中對象的引用**。
* 第三階段:識別被老年代對象指向的Eden區中的對象,這些被指向的Eden中對象被認為是存活的對象。
* 第四階段:復制對象(**使用的是復制算法**),對象數被遍歷,Eden區region中存活的對象會被復制到Survivor區中的region,Survivor region中的存活對象如果年齡未達到閾值,年齡+1,達到閾值會被復制到Old region,如果Survivior的空間不夠用,Eden中的部分數據會直接晉升到老年代。
* 第五階段:處理Soft、Weak、Phantom、Final、JNI Weak等引用,最終Eden區的數據為空,這些空的region將會等待對象的分配,GC停止工作,目標內存中的對象也都是連續的,沒有內存碎片。
* 老年代并發標記
* **當堆空間的內存占用達到閾值(-XX:InitiatingHeapOccupancyPercent,默認45%)就開始老年代的并發標記過程**。
* 初始標記階段:**標記GC Roots直接可達的對象,也就是直接引用關系對象**,會發生STW(由于是直接可達的對象的標記,所以暫停時間很短),**并且會觸發一次Young GC**
* 根區域的掃描(Root Region Scanning):G1掃描Survivor區直接可達的老年代區域對象,并標記被引用的對象。這一個過程**必須在Young GC之前完成(因為Young GC會操作Survivor區中的對象)**。
* 并發標記(Concurrent Marking):在整個堆中進行并發標記(與程序線程并發執行),**此過程可能會被Young GC打斷**,在并發標記階段中,**若發現某些region中所有對象都是垃圾,那這個region就會被立即回收**,同時并發標記過程中,會**計算每個region的對象活性(該region存活對象的比例,G1垃圾回收的時候并不是所有region都會參與回收的,根據回收的價值高低來優先回收價值較高的region)**。
* 再次標記:由于并發標記階段是收集器的標記線程和程序線程并發執行的,需要進行再次標記,修正上一次的標記結果,可以理解為增量補償標記。會出現STW(暫停時間較短)。G1采用的是比CMS跟快的初始快照算法:snapshot-at-the-beginning(SATB)
* 獨占清理:計算各個region的存活對象和GC回收比例,并進行排序(回收價值高低排序),識別可以混合回收的區域。為下階段做鋪墊,會發生STW。**需要注意的是這個階段實際上并不會做垃圾的回**收。
* 并發清理階段:識別并清理完成空閑的區域
* 混合回收

* 包括年輕代和老年代的垃圾回收
* 標記完成后馬上開始垃圾的回收。對于一個混合的回收過程,G1從老年代移動存活的對象到空閑區域,這些空閑的區域變成了老年代region。當越來越多的對象晉升到老年代region的時候,為了避免堆內存被耗盡,就會觸發以哦個混合垃圾收集Mixed GC,該算法并不是一個Old GC也不是Full GC,除了回收整個Young region之外,還會回收一部分Old region,**部分的region垃圾回收設計可以對垃圾回收的耗時進行控制**。
* 在并發標記結束之后,老年代中能夠完全確認為垃圾的region中的內存分段被回收了,部分為垃圾的region中內存分段也被計算出來了,默認情況下,這些老年代的內存分段會被分為8次回收(**可以通過-XX:G1MixedGCCountTarget設置**)。
* 混合回收的回收集包括1/8的老年代的內存分段,Eden區內存分段,Survivor內存分段,**混合回收的算法和年輕代回收的算法完全一致**。
* 混合回收并不一定要進行8次,有一個**閾值設置:-XX:G1HeapWastePercent,默認值10%,代表允許整個堆內存中有10%的內存可以被浪費,意味著如果發現可以回收的垃圾占對內存的比例低于10%,則不進行混合回收**,因為GC花費的時間相對于較少的垃圾回收來說得不償失。
* **由于老年代的內存分段默認分為8次回收,G1會優先回收垃圾多的內存分段,垃圾占內存分段比例越高的會優先被回收**。并且有**一個閾值決定內存分段是否被回收:-XX:G1MixedGCLiveThresholdPercent,默認為65%,代表垃圾占內存分段比例要達到65%來回被回收**,如果垃圾占比太低,意味著存活的對象多,復制算法就會花費更多的時間區復制存活的對象。
* 必要的情況下(對象分配速度遠大于回收速度),Full GC仍然會觸發(Full GC的成本較高,單線程,性能差,STW時間長)
* 堆內存太小、對象分配速度遠大于回收速度等原因都可以導致G1在復制存活對象的時候沒有空閑的內存分段可用,最終造成Full GC的觸發。
- 前言
- Write once, run anywhere
- 概述
- JAVA虛擬機
- JVM整體結構
- JVM架構模型
- JVM虛擬機分類
- HotSpot VM
- JRockit
- IBM-J9
- Azul/zing VM
- Taobao VM
- Dalvik VM
- Graal VM
- JAVA源碼編譯機制
- Javac編譯器
- 分析和輸入到符號表
- 注解處理
- 語義分析和生成class文件
- ECJ編譯器
- 類執行機制
- 字節碼解釋執行
- 棧頂緩存
- 部分棧幀共享
- 編譯執行
- 即時編譯器
- C1 Compiler
- C2 Compiler
- Graal編譯器
- C1與C2編譯器
- AOT
- 編譯優化
- 字符串優化
- 方法內聯
- 逃逸分析
- 同步消除
- 標量替換
- 棧上分配
- 去虛擬化/逆優化
- 多層編譯
- JVM編譯策略
- OSR編譯
- 冗余削除
- CodeCache
- 常量編譯優化
- JVM運行時數據區
- 程序計數器
- JAVA虛擬機棧
- 棧幀
- 局部變量表
- 操作數棧
- 本地方法棧
- Java調用native方法
- JVM Stacks && Native Stacks
- 堆-Heap
- 方法區(Method Area)
- 運行時常量池
- 常量傳播優化
- MetaSpace
- 直接內存
- StackOverflowError
- 遞歸方法
- OutOfMemoryError
- 本地內存溢出
- 執行引擎
- 運行時數據區關聯關系
- jdk8內存結構
- JMM內存模型
- JAVA內存模型
- JMM八種操作指令
- 內存屏障
- 指令重排
- as-if-serial語義
- Happen-Before規則
- 數據依賴性
- 原子性、可見性與有序性
- 偽共享
- CPU三級緩存
- 緩存行
- MESI協議
- Java中的偽共享
- ConcurrentHashMap偽共享解決方案
- 虛擬機對象
- 對象創建原理
- 對象內存布局
- 對象頭
- 實例數據
- 對象的訪問定位
- 垃圾收集器與內存分配策略
- GC相關概念
- TLAB
- JVM GC工作原理
- 內存管理
- JAVA引用分類
- 死亡標記
- 回收方法區
- 三色標記算法
- 垃圾收集算法
- 標記-清除算法
- 標記-整理算法
- 復制算法
- 分代收集算法
- HotSpot算法實現
- STW
- 垃圾收集器
- 常見的垃圾收集器
- 垃圾收集器分類
- Serial收集器
- Serial Old收集器
- ParNew收集器
- Parallel Scavenge收集器
- Parallel Old收集器
- CMS收集器
- CMS完整收集過程
- Card Table
- G1收集器
- 分代收集
- 空間整合
- 可預測的停頓時間模型
- G1&CMS
- 主要參數說明
- G1適用場景
- Remembered Set
- G1垃圾回收的過程
- G1優化建議
- Shenandoah
- ZGC
- 垃圾收集器特點
- GC日志
- GC策略的評價指標
- jvm card table數據結構
- 對象生存軌跡
- 類文件結構
- 魔數
- 版本號
- 常量池
- 訪問標志
- 父類索引
- 接口集合
- 字段集合
- 方法集合
- 屬性集合
- 類加載機制與類的初始化
- Java代碼執行流程
- 類加載過程
- 抽象類ClassLoader
- 常見類加載器
- BootstrapClassLoader
- 自定義類加載器
- 線程上下文類加載器
- 雙親委派模型
- Tomcat類加載機制
- ServiceLoader
- 類的初始化
- 常見的JVM類加載異常
- ClassNotFoundException
- NoClassDefFoundError
- LinkageError
- ClassCastException
- 虛擬機性能調優監控與故障處理工具
- CPU利用率高/飆升
- 排查及解決方案
- 上下文切換
- GC問題定位解決方案
- prommotion failed
- FullGC頻繁
- youngGC
- 內存問題
- 內存溢出和內存泄漏
- 內存溢出
- 棧溢出
- 堆溢出
- 對外內存溢出
- 內存泄漏
- 磁盤問題
- 線上問題解決方案
- 不定期出現的接口耗時現象
- 線程池異常
- 死鎖問題
- JVM調優
- jvm參考配置
- jvm-jstat
- jvm-jmap
- jvm-jstack
- jinfo
- jps
- 虛擬機的退出
- Shutdown Hook
- JVM指令
- 附錄
- 常用JVM指令
- Class文件版本號
- Class文件格式
- 方法訪問標識
- jvm常量池
- 類或接口的訪問標識
- 描述符標識字符含義
- 字段訪問標識
- Java程序與Docker容器環境
- 基準測試