java_opts gc回收器_java CMS垃圾回收升级G1回收器实践

本文介绍了Java CMS与G1垃圾收集器的对比,强调了G1在处理大堆、停顿时间和内存碎片上的优势。通过一个实际案例展示了CMS升级到G1的原因和效果,包括降低GC次数和耗时。同时,提供了G1的升级步骤、核心参数介绍及调优建议,帮助读者理解何时及如何切换到G1垃圾回收器。
摘要由CSDN通过智能技术生成

一、什么是G1

1578883622697-ef25ce5c-6fcc-4178-825e-c9e484771e63.png

G1(Garbadge First Collector)作为一款JVM最新的垃圾收集器,可以解决CMS中Concurrent Mode Failed问题,尽量缩短处理超大堆的停顿,在G1进行垃圾回收的时候完成内存压缩,降低内存碎片的生成。

G1在堆内存比较大的时候表现出比较高吞吐量和短暂的停顿时间,而且已成为Java 9的默认收集器。未来替代CMS只是时间的问题。

二、CMS与G1对比

CMS (Concurrent Mark Sweep)收集器

1578883651750-2c117d34-16dc-4aa0-b05a-7e6108d72144.png

运作流程

•初始标记、重新标记要停顿其他用户线程

•初始标记仅仅只是标记出GC ROOTS能直接关联到的对象,速度很快

•并发标记阶段是进行GC ROOTS 根搜索算法阶段,会判定对象是否存活

•重新标记阶段则修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录->停顿时间会比初始标记阶段稍长,但比并发标记阶段要短

G1(Garbadge First Collector)收集器

1578883681872-bc91f748-512e-45f3-b672-1e9372c6bd57.png

运作流程

初始标记:标记出所有与根节点直接关联引用对象、需要STW

并发标记:遍历之前标记到的关联节点,继续向下标记所有存活节点。在此期间所有变化引用关系的对象,都会被记录在Remember Set Logs中

最终标记:标记在并发标记期间,新产生的垃圾。需要STW

筛选回收:根据用户指定的期望回收时间回收价值较大的对象,需要STW

CMS收集器的三个显著缺点:

•CMS收集器对CPU资源非常敏感

在并发阶段,虽然不会导致用户线程停顿,但是会占用CPU资源而导致引用程序变慢,总吞吐量下降。CMS默认启动的回收线程数是:(CPU数量+3) / 4。

•CMS收集器无法处理浮动垃圾

可能出现“Concurrent Mode Failure“,失败后而导致另一次Full GC的产生

由于CMS并发清理阶段用户线程还在运行,伴随程序的运行自热会有新的垃圾不断产生,这一部分垃圾出现在标记过程之后,CMS无法在本次收集中处理它们,只好留待下一次GC时将其清理掉。这一部分垃圾称为“浮动垃圾”

需要预留一部分内存空间提供并发收集时的程序运作使用

•基于“标记-清除”算法实现的收集器,产生大量碎片

空间碎片太多时,将会给对象分配带来很多麻烦,比如说大对象,内存空间找不到连续的空间来分配不得不提前触发一次Full GC->提供了一个-XX:UseCMSCompactAtFullCollection开关参数->用于在Full GC之后增加一个碎片整理过程->通过-XX:CMSFullGCBeforeCompaction参数设置执行多少次不压缩的Full GC之后,跟着来一次碎片整理过程。

G1相对CMS的优点:

•停顿时间可以预测:

G1可以指定时间,在指定时间内只回收部分价值最大的空间,而CMS需要扫描整个年老代,无法预测停顿时间

•无内存碎片:

垃圾回收后会整合空间,CMS采用"标记-清理"算法,存在内存碎片

•筛选回收阶段不会产生"浮动垃圾":

由于只回收部分region,所以STW时间我们可控,所以不需要与用户线程并发争抢CPU资源,而CMS并发清理需要占据一部分的CPU,会降低吞吐量。

由于STW,所以不会产生"浮动垃圾"(即CMS在并发清理阶段产生的无法回收的垃圾)

三、我的应用是否适合升级G1?

以下场景下G1更适合

1.服务端多核CPU、JVM内存占用较大的应用(至少大于4G)

2.应用在运行过程中会产生大量内存碎片、需要经常压缩空间

3.想要更可控、可预期的GC停顿周期;防止高并发下应用雪崩现象

四、CMS升级G1案例

升级背景

在压测过程中发现aicloud-proxy-player存在GC时长长,而且次数多的问题。根据GC日志和观察分析发现:均是由于年轻代用满触发YGC,而且多次YGC后没有新对象晋升至老年代。此时年轻代和老年代的内存配比是1:1。dump下来了内存的堆栈信息。发现大量存在着小对象,即byte和String等对象的新建和释放,这些对象在每次进行线程请求后会生成,生成后均是一次性使用。所以当并发越高,请求越大会越大量的生成一次性的小对象,YGC也会越来越频繁。

升级G1原因

1.进行碎片处理,内存空间整理,减少消耗,对于大量小对象十分有利;

2.采用Region模式,不再GC的时候进行内存对象的拷贝,减少耗时;

3.可设置停顿时间,更大的好处在于年轻代和老年代的动态大小分配,对于我们没用的老年代很有效;

4.UseStringDeduplication 使用G1特性的去除重复的字符串,减少内存开销

升级G1效果

显著降低了GC次数,减少了GC的耗时

1578883789450-2b400ef9-4b2b-447e-acdd-227f5ed400e7.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当Docker容中的JAVA_OPTS参数没有生效时,可能存在以下几种情况: 1. 完整的JAVA_OPTS参数被其他参数覆盖:在启动Docker容时,可能传入了其他的JVM参数,比如通过环境变量或命令行参数传递给Java应用程序。这些额外的参数可能会覆盖容中设置的JAVA_OPTS参数,导致其无法生效。可以检查启动命令和相关配置,确保没有传入其他参数。 2. 容Java应用程序没有正确读取JAVA_OPTS参数:在Java应用程序中,需要通过System.getProperty()或System.getenv()等方法来读取JAVA_OPTS参数,并将其作为JVM参数传递给Java虚拟机。如果应用程序没有正确读取这些参数,就无法生效。可以检查代码中读取参数的逻辑,确保正确获取并传递JAVA_OPTS参数。 3. 容环境和执行Java应用程序的用户权限问题:容内可能存在用户权限问题,可能导致Java应用程序无法正确读取JAVA_OPTS参数。例如,容中运行Java应用程序的用户可能没有足够的权限读取系统环境变量。可以检查容内的用户权限,并确保权限足够。 4. 容内的JAVA_OPTS参数设置错误:容中配置的JAVA_OPTS参数可能有错误,导致其无法生效。可以检查JAVA_OPTS参数的格式、写法和值是否正确。 以上是可能导致Docker容中的JAVA_OPTS参数无法生效的几种情况,可以逐一排查,找出具体原因,并进行相应的修复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值