【jvm】young gc full gc

JVM内存管理:YoungGC和FullGC的触发条件与机制详解,
本文详细阐述了JVM中YoungGC和FullGC的触发条件,包括内存满、空间不足、元空间阈值、以及与CMS收集器相关的触发机制。同时提到了与MinorGC、OldGC和MajorGC的关系以及生产环境的最佳实践。

何时触发YoungGC或FullGC

YoungGC的触发时常在发生,当新生代的Eden区满了之后就会触发YoungGC。

FullGC在多个情况下都会被触发:

1、发生Young GC之前进行检查,如果“老年代可用的连续内存空间” < “新生代历次Young GC后升入老年代的对象总和的平均大小”,说明本次Young GC后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,此时会触发FullGC

2、当老年代没有足够空间存放对象时,会触发一次FullGC

3、如果元空间区域的内存达到了所设定的阈值-XX:MetaspaceSize=,也会触发FullGC。

4.显式调用System.gc() 或者Runtime.gc() 

几个触发老年代FULL GC的时机

1、老年代可用内存小于新生代全部对象的大小,如果没开启空间担保参数,会直接触发Full GC,所以一般空间担保参数都会打开。

2、老年代可用内存小于历次新生代GC后进入老年代的平均对象大小,此时会提前Full GC;但是"-XX:HandlePromotionFailure"参数,在JDK 1.6以后就被废弃了,所以现在一般都不会在生产环境里设置这个参数了。在JDK 1.6以后,只要判断"老年代可用空间"大于"新生代对象总和"或者"老年代可用空间"大于"历次Minor GC升入老年代对象的平均大小",两个条件满足一个,就可以直接进行Minor GC,不需要提前触发Full GC了。

3、是新生代Minor GC后的存活对象大于Survivor,那么就会进入老年代,此时老年代内存不足,触发Full GC。这里的不足就是判断条件后还是不足或者经过判断后进行YGC后放入老年代此时的空间不足,然后进行Full GC,就会出现频繁Full GC。达到一定情况后,就会OOM了。

4、是如果用的是CMS收集器,老年代可用内存大于历次新生代GC后进入老年代的对象平均大小,但是老年代已经使用的内存空间超过了("-XX:CMSInitiatingOccupancyFaction=92%"JDK6默认值 )这个参数指定的比例,也会自动触发Full GC。

 Minor GC、Young GC、Full GC、Old GC、Major GC、Mixed GC 一文搞懂

JVM young gc和full gc触发条件_younggc触发条件-优快云博客

JVM:29 面试题:Young GC和Full GC分别在什么情况下会发生?_young gc 情况-优快云博客

各类GC及触发条件_concurrent gc-优快云博客 

JVM(Java Virtual Machine)中,**Full GC**(Full Garbage Collection)是指对整个堆内存(包括年轻代、老年代)以及方法区(元空间或永久代)进行的垃圾回收。它通常耗时较长,会导致应用程序**“Stop-The-World”**(STW),即所有应用线程暂停,因此应尽量避免频繁发生。 --- ## 🔥 一、什么是 Full GC? - **Full GC** 是一次全局性的垃圾回收: - 回收 **年轻代(Young Generation)** - 回收 **老年代(Old Generation)** - 回收 **方法区 / 元空间(Metaspace)** - 它由不同的 GC 算法触发,常见的如 Serial Old、Parallel Old、CMS 的最终阶段、G1 的 Mixed GCFull GC 阶段等。 - 触发后会**暂停所有用户线程**,直到清理完成。 > ⚠️ 注意:虽然名字叫 "Full GC",但某些情况下可能只是 Major GC(仅老年代回收),但在日志中仍被标记为 Full GC。 --- ## 🧨 二、Full GC 触发的主要原因 以下是导致 JVM 执行 Full GC 的常见原因: --- ### 1. **老年代空间不足(最常见)** 当老年代没有足够空间容纳从年轻代晋升的对象时,会尝试触发一次 Full GC。 #### 常见场景: - 大量对象提前晋升到老年代(如 Survivor 区太小) - 长期存活对象过多 - 年轻代 GC 后有大批对象要进入老年代,但老年代放不下 ```text java.lang.OutOfMemoryError: Java heap space ``` 👉 此错误前往往伴随多次 Full GC。 --- ### 2. **System.gc() 被显式调用** Java 中调用 `System.gc()` 会建议 JVM 执行一次 Full GC(除非禁用)。 #### 示例代码: ```java System.gc(); // 显式请求 GC ``` #### 如何避免? - 使用 JVM 参数禁止响应此调用: ```bash -XX:+DisableExplicitGC ``` - 或者在生产环境中严格禁止使用 `System.gc()`。 --- ### 3. **元空间(Metaspace)空间不足** JDK 8+ 使用 **Metaspace** 替代了永久代(PermGen)。如果类加载过多(如动态生成类、反射、OSGi、热部署框架),可能导致 Metaspace 耗尽。 #### 触发条件: - Metaspace 占用接近阈值(`MaxMetaspaceSize`) - 默认情况下,Metaspace 扩容失败时会触发 Full GC 来尝试卸载类(通过 CMS 或 G1) #### 相关参数: ```bash -XX:MaxMetaspaceSize=256m # 设置上限 -XX:MetaspaceSize=64m # 初始大小,达到后触发首次 GC ``` --- ### 4. **CMS GC 时出现 “Concurrent Mode Failure”** 如果你使用的是 **CMS 收集器**(老年代),它本意是并发回收,不暂停应用线程。但如果在 CMS 执行过程中,老年代空间不足以容纳新晋升的对象,就会退化为 **Serial Old** 进行 Full GC。 #### 日志特征: ```text [GC (CMS Initial Mark) ... [Full GC (Concurrent Mode Failure) ``` #### 解决方案: - 增加老年代大小 - 提前启动 CMS:调整 `-XX:CMSInitiatingOccupancyFraction` - 减少对象晋升速度(优化对象生命周期) --- ### 5. **晋升失败(Promotion Failed)** 在 Minor GC 期间,如果 Survivor 区无法容纳存活对象,这些对象将尝试晋升到老年代。但如果老年代**连续空间不足**,即使总空间够,也可能因无法分配大对象而失败。 #### 原因: - 老年代碎片化严重(尤其使用 CMS 时) - 没有足够的连续空间存放大对象 此时 JVM 会触发 Full GC 尝试整理老年代空间。 --- ### 6. **堆内存分配担保失败(Allocation Failure)** JVM 在每次 Minor GC 前会检查老年代最大可用连续空间是否大于“年轻代所有对象总”或“历次晋升平均大小”。如果不够,就提前触发 Full GC(称为“分配担保”机制)。 这属于一种预防性策略。 --- ### 7. **G1 GC 中的 Full GC(应极力避免)** G1 正常情况下不会执行 Full GC,但在以下情况会发生: - **并发标记阶段来不及完成**,而堆空间又快满了 - **晋升时老年代空间不足**,且 G1 无法及时完成 Mixed GC 清理 - **巨型对象(Humongous Object)** 分配失败 此时 G1 会退回到单线程 Full GC(通常是 **SATB + Mark-Sweep Compact**),非常慢。 #### 日志示例: ```text [Full GC (Ergonomics) ...] ``` #### 预防措施: - 调整 `-XX:InitiatingHeapOccupancyPercent` - 增加堆大小 - 控制 Humongous 对象分配 --- ### 8. **Direct Memory 导致的间接 Full GC(NIO 场景)** 使用 `ByteBuffer.allocateDirect()` 分配堆外内存时,不受堆限制,但其释放依赖于 `Cleaner`(基于 PhantomReference),而 Cleaner 的触发依赖于 **老年代 GC**。 如果长时间不触发老年代 GC,则 Direct Memory 无法及时释放 → 内存泄漏 → 最终 OOM → 可能触发紧急 Full GC。 --- ## 📊 三、如何监控诊断 Full GC? ### 1. 开启 GC 日志(强烈推荐) ```bash -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10M ``` ### 2. 查看关键字段 在 GC 日志中查找: ```text [Full GC [GC (Allocation Failure) --> 可能引发 Full GC [GC (Metadata GC Threshold) --> Metaspace 触发 [Full GC (Ergonomics) --> JVM 自动决策 [Full GC (System.gc()) --> 显式调用 [Full GC (Concurrent Mode Failure) --> CMS 失败 ``` ### 3. 使用工具分析 - **jstat**: 实时查看 GC 统计 ```bash jstat -gcutil <pid> 1s ``` - **VisualVM / JConsole / Prometheus + Grafana** - **GCViewer / GCEasy.io**:上传日志文件自动分析 --- ## ✅ 四、如何减少或避免 Full GC? | 问题 | 解决方案 | |------|----------| | 老年代空间不足 | 增大 `-Xmx` `-Xms`;优化对象生命周期 | | 对象过早晋升 | 增大 Survivor 区:`-XX:SurvivorRatio` | | Metaspace 不足 | 增大 `-XX:MaxMetaspaceSize`;检查类加载泄漏 | | System.gc() 调用 | 添加 `-XX:+DisableExplicitGC` | | CMS 并发失败 | 提前触发 CMS:`-XX:CMSInitiatingOccupancyFraction=70` | | G1 Full GC | 调整 IHOP:`-XX:InitiatingHeapOccupancyPercent=45` | | 堆外内存泄漏 | 限制 Direct Memory:`-XX:MaxDirectMemorySize`;手动 `clean()` | --- ## 🧪 五、实战排查步骤 1. **确认是否真的发生了 Full GC** 查看 GC 日志或使用 `jstat -gc <pid>`。 2. **定位触发原因** 看日志中的括号说明:`(System.gc())`, `(Metadata GC Threshold)` 等。 3. **分析内存分布** 使用 MAT(Memory Analyzer Tool)分析 heap dump,看是否有内存泄漏。 4. **优化代码与配置** - 减少大对象创建 - 避免长生命周期持有无用对象 - 合理设置堆参数 5. **选择合适的 GC 器** - 吞吐优先:Parallel GC - 低延迟:G1、ZGC、Shenandoah ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值