Full GC的认识、预防和定位

本文详细介绍了JVM中的FullGC过程,包括新生代和老年代GC的触发机制,以及FullGC对程序性能的影响。同时提供了防止FullGC的建议和定位FullGC问题的方法,包括使用工具进行内存分析和故障排查。

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨
👀👀👀 个人博客:小奥的博客
👍👍👍:个人优快云
⭐️⭐️⭐️:传送门
🍹 本人24应届生一枚,技术和水平有限,如果文章中有不正确的内容,欢迎多多指正!
📜 欢迎点赞收藏关注哟! ❤️

JVM之带你认识Full GC

一. 主要的GC形式

JVM在进行GC时,并非每次都对所有内存区域进行垃圾回收,大部分回收的都是指新生代。

针对Hotspot VM的实现,它里面的GC按照回收区域又分为两大种类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC)

  • 部分收集(Partial GC):不是完整收集整个Java堆的垃圾收集。其中又分为:

    • 新生代收集(Minor GC / Young GC):只是新生代的垃圾收集
    • 老年代收集(Major GC / Old GC):只是老年代的圾收集。
      • 目前,只有CMS GC会有单独收集老年代的行为。
      • 注意,很多时候Major GC会和Full GC混淆使用,需要具体分辨是老年代回收还是整堆回收。
    • 混合收集(MixedGC):收集整个新生代以及部分老年代的垃圾收集。
      • 目前,只有G1 GC会有这种行为
  • 整堆收集(Full GC):收集整个java堆和方法区的垃圾收集。

1.1 新生代GC(Minor GC)触发机制

  • 当新生代空间不足时,就会触发Minor GC,这里的新生代空间不足是指Eden区满,Survivor区满不会引发GC。(每次Minor GC会清理年轻代的内存)
  • 因为Java对象大多数都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。
  • Minor GChi引发 STW,暂停用户其他线程,等垃圾回收结束,才会恢复用户线程。

1.2 老年代GC(Major GC 、Full GC)触发机制

(1)Major GC触发时机

  • 出现了Major GC,经常会伴随至少一次的Minor GC。也就是说老年代空间不足时,会现场时触发Minor GC,如果之后空间还不足,则触发Major GC。
  • Major GC的速度一般比Minor GC慢10倍以上,STW的时间更长。
  • 如果Major GC后,内存还不足,则会产生OOM异常。

(2)Full GC触发时机

  • 调用System.gc()时,系统建议执行Full GC,但是不一定会执行。
  • 老年代空间不足时
  • 方法区空间不足时
  • 通过Minor GC后进入老年代的平均大小大于老年代的可用内存
  • 由Eden区、survivor space0(From Space)区向survivor space1(To Space)区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

R 大的回答

二、Full GC的一些问题

2.1 Full GC对程序的影响

Full GC产生的影响主要是:

在发生FULL GC的时候,意味着JVM会安全的暂停所有正在执行的线程(Stop The World),来回收内存空间,在这个时间段内,所有除了回收垃圾的线程外,其他有关JAVA的程序,代码都会静止,反映到系统上,这个过程会导致应用程序暂停执行,造成一定的性能损失和响应延迟。

比如会产生如下的问题:

  • CPU满载告警
  • API响应时间过长
  • 内存反复波动
  • fullgc告警

2.2 如何防止Full GC

《深入理解JVM虚拟机》中给出了这样的建议:

控制Full GC频率的关键是老年代的相对稳定,这主要取决于应用中绝大多数对象能否符合“朝生夕灭”的原则,即大多数对象的生存时间不应当太长,尤其是不能有成批量的、长生存时间的大对象产生,这样才能保障老年代空间的稳定。

所以总结下来,在实际的工作中,我们尽量减少短时间内大量对象的产生,比如重复利用的对象我们可以使用单例模式来减少重复创建,尽量保证老年代的稳定。

2.3 如何定位Full GC

线上服务的GC问题,是Java程序非常典型的一类问题,但是对于经验不足的我们来说还是比较难的,所以我带大家一起学习下,如何系统地定位Full GC的问题。

这里给大家推荐一篇实战排查的文章,博主也是通过这篇文章来学习的。

线上服务的Full GC问题排查,看这篇就够了!

大致的步骤就是:

  • 首先查看我们JVM的配置
  • 通过内存分析工具查看老年代的内存变化,排查是内存泄漏还是内存溢出
  • 通过jmp查看内存映射信息
  • 进一步查看dump内存文件进行分析
  • 通过代码分析具体的对象

另外我们一般可以使用一些工具来进行辅助排查问题:

  • jps: 查看本机java进程
  • jstack: 打印线程的栈信息,制作线程dump文件
  • jmap:打印内存映射信息,制作堆dump文件
  • jstat:性能监控工具
  • jhat:内存分析工具,用于解析堆dump文件并以适合人阅读的方式展示出来
  • jconsole: 简易的jvm可视化工具

这些工具主要是可以查看dump映射文件,从而排查到具体的对象,进而我们再结合代码进行检查即可。

三、一些参考案例

10-27
<think>我们正在讨论Java的垃圾回收机制,特别是Full GC。根据用户的要求,我需要解释Full GC的含义、触发原因以及影响。同时,我需要参考之前提供的引用内容,并在回答中自然地添加引用标识。 回顾引用内容: 引用[1]详细说明了Full GC的触发条件,包括: - 显式调用System.gc() - 老年代空间不足 - 方法区(Metaspace)空间不足 - 大对象分配失败 - 晋升失败(Minor GC后Survivor区对象晋升到老年代时空间不足) 引用[2]则提到如何避免Full GC,例如通过合理设置新生代老年代的比例(使用-XX:NewRatio参数)。 因此,我的回答结构如下: 1. **Full GC的含义**:Full GC是Java虚拟机(JVM)中的一种垃圾回收过程,它会清理整个堆内存(包括新生代老年代)以及方法区(或元空间)。与只针对新生代的Minor GC不同,Full GC的范围更广,耗时更长。 2. **触发Full GC的原因**:基于引用[1],我将详细列出触发条件,每个条件都附带解释,并在末尾添加引用标识[^1]。 3. **Full GC的影响**:主要影响是性能,因为Full GC会暂停所有应用线程(Stop-The-World),导致应用程序停顿。频繁的Full GC会严重影响系统响应时间吞吐量。 4. **如何避免Full GC**:参考引用[2],可以调整JVM参数(如-XX:NewRatio)来优化内存分配,减少Full GC的发生。同时,还可以建议其他方法,如增大堆大小、优化代码等。 最后,按照用户要求,生成相关问题。 注意:在回答中,如果有数学表达式(比如在解释内存比例时),我需要按照系统级指令使用$...$或$$...$$格式。例如,当提到新生代老年代的比例时,可以写成比例参数设置为$2$(即-XX:NewRatio=2)。 现在,构建回答内容: ### Full GC的含义 Full GC(完全垃圾回收)是Java虚拟机(JVM)中一种全局性的垃圾回收过程,它会同时清理**新生代(Young Generation)**、**老年代(Old Generation)** 以及**元空间(Metaspace,Java 8+)** 中的无用对象[^1]。与仅针对新生代的Minor GC相比,Full GC的回收范围更广,执行时间更长,通常会导致明显的应用程序停顿(Stop-The-World)。 ### 触发Full GC的原因 根据JVM的内存管理机制,Full GC的触发条件主要包括: 1. **老年代空间不足** 当老年代剩余空间无法容纳从新生代晋升的对象时,会触发Full GC[^1]。例如: $$ \text{老年代剩余空间} < \text{晋升对象总大小} $$ 2. **显式调用`System.gc()`** 代码中调用`System.gc()`会建议JVM执行Full GC,但JVM可能忽略该请求(取决于`-XX:+DisableExplicitGC`参数配置)[^1]。 3. **元空间(Metaspace)不足** 在Java 8及以上版本,如果元空间(存放类元数据)的内存耗尽,且无法再扩展,会触发Full GC[^1]。 4. **大对象分配失败** 尝试分配大对象(如超大数组)时,若新生代无法容纳且老年代空间也不足,会直接触发Full GC[^1]。 5. **晋升失败(Promotion Failure)** Minor GC后,Survivor区中的存活对象需要晋升到老年代,但老年代空间不足,此时会触发Full GC[^1]。 --- ### Full GC的影响 Full GC对应用程序性能有显著负面影响: - **长时间停顿(Stop-The-World)**:Full GC会暂停所有应用线程,停顿时间可达秒级甚至分钟级,影响系统响应速度。 - **吞吐量下降**:频繁Full GC会占用大量CPU资源,降低有效业务处理能力。 - **内存碎片问题**:Full GC可能引发内存碎片化,进一步加剧后续GC压力。 --- ### 避免Full GC的优化策略 1. **调整堆内存比例** 通过`-XX:NewRatio`参数合理设置新生代与老年代的比例(例如$2$表示老年代是新生代的2倍),减少对象过早晋升到老年代的概率[^2]。 ```bash java -XX:NewRatio=2 -jar app.jar ``` 2. **增大堆内存总量** 适当增加`-Xmx`(最大堆内存)`-Xms`(初始堆内存)的值,为老年代元空间预留更多空间。 3. **避免代码中调用`System.gc()`** 可通过添加JVM参数`-XX:+DisableExplicitGC`禁用显式GC调用。 4. **元空间监控与扩展** 设置`-XX:MaxMetaspaceSize`限制元空间上限,避免无限制增长触发Full GC。 5. **选择低停顿垃圾回收器** 如G1(Garbage-First)或ZGC,通过增量回收减少Full GC频率。 --- §§相关问题§§ 1. 如何通过JVM日志分析Full GC的触发原因? 2. G1垃圾回收器如何减少Full GC的发生? 3. 元空间(Metaspace)的内存管理机制是怎样的? 4. 哪些代码写法会导致频繁触发Full GC? [^1]: Full GC触发条件的详细技术说明 [^2]: JVM内存比例调整对Full GC的影响 </think>### Full GC的含义与机制 **Full GC**(完全垃圾回收)是 Java 虚拟机(JVM)中一种全局性的垃圾回收过程,涉及清理整个堆内存(包括**新生代**、**老年代**)以及**方法区**(Java 8+ 为 Metaspace)[^1]。其核心目标是释放不再使用的对象内存,避免内存溢出(OOM)。与仅针对新生代的 **Minor GC** 不同,Full GC 的回收范围更广、耗时更长(通常可达秒级),且会暂停所有应用线程(Stop-The-World)。 --- ### Full GC 的触发原因 基于 JVM 内存管理机制,触发条件主要包括: 1. **老年代空间不足** - 当老年代剩余空间无法容纳从新生代晋升的对象时触发[^1],数学表示为: $$ \text{老年代剩余空间} < \text{晋升对象总大小} $$ - 常见诱因:长期存活对象积累(如缓存未清理)或内存泄漏。 2. **显式调用 `System.gc()`** - 开发者主动调用 `System.gc()` 可能建议 JVM 执行 Full GC,但 JVM 可忽略该请求(取决于 `-XX:+DisableExplicitGC` 配置)[^1]。 3. **Metaspace 空间不足** - Java 8+ 中,Metaspace(存放类元数据)耗尽时可能触发 Full GC[^1]。 - 常见于频繁动态生成类(如反射、CGLIB 代理)。 4. **大对象分配失败** - 对象大小超过新生代单块区域(如 Eden 区)容量,且老年代无法容纳该对象时触发[^1]。 5. **晋升失败(Promotion Failure)** - Minor GC 后,Survivor 区存活对象需晋升至老年代,但老年代空间不足[^1]。 --- ### Full GC 的影响 | **影响维度** | **具体表现** | |--------------------|-----------------------------------------------------------------------------| | **性能** | 应用线程暂停(Stop-The-World),响应延迟骤增,吞吐量下降。停顿时间与堆大小成正比。 | | **系统稳定性** | 频繁 Full GC 导致服务超时,甚至引发雪崩故障。 | | **内存碎片** | Full GC 可能加剧老年代内存碎片化,进一步降低后续内存分配效率。 | | **资源消耗** | 高 CPU 占用(GC 线程全力工作),挤压业务计算资源。 | --- ### 避免 Full GC 的关键优化策略 1. **调整内存区域比例** - 通过 `-XX:NewRatio` 合理分配新生代与老年代比例(例如 `-XX:NewRatio=2` 表示老年代占堆的 $2/3$)[^2],延缓对象晋升速度。 - 示例: ```bash java -XX:NewRatio=2 -Xmx4g -jar app.jar ``` 2. **增大堆空间或 Metaspace** - 适当提高 `-Xmx`(最大堆内存) `-XX:MaxMetaspaceSize`(元空间上限)。 3. **选择低停顿垃圾回收器** - 使用 G1(Garbage-First)或 ZGC,通过**分区回收****并发标记**减少 Full GC 频率。 - 示例: ```bash java -XX:+UseG1GC -jar app.jar ``` 4. **代码层面优化** - 避免调用 `System.gc()`。 - 减少大对象分配(如拆分大数组)。 - 及时清理无引用对象(如缓存设置 TTL)。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值