• 1111111111


    五、垃圾回收器调优

    5.1 预备知识

            1、掌握 GC 相关的 VM 参数,会基本的空间调整

            2、掌握相关的工具

            3、明白一点:调优和应用、环境有关,没有放之四海而皆准的法则。

    5.2 调优领域

            内存、锁竞争、cpu 占用、io

    5.3 确定目标

            需要根据你的实际业务场景选择合适的回收器,如果是互联网企业,可能更关注的是低延迟,即响应时间更短,可以选择 CMSG1ZGC 等。

            如果是进行科学运算,可能追求的是高吞吐量,延长一点点响应时间也是没有问题的,只能选择 ParallelGC。

    5.4 最快的 GC 是不发生 GC

            查看 FullGC 前后的内存占用,如果你的虚拟机经常发生 GC,需要考虑下面几个问题

            1、数据是不是太多了?是不是加载了不必要的数据到内存里面。

            2、数据表现是否太臃肿?能用基本类型就不用包装类型。

            3、是否存在内存泄漏?一直向集合里面添加元素但不移除。

    5.5 新生代调优

    5.5.1 新生代特点

            1、所有的 new 操作的内存分配非常廉价

            2、死亡对象的回收代价是零

            3、大部分对象用过即死

            4、Minor GC 的时间远远低于 Full GC

    5.5.2 越大越好吗

            使用 -Xmn 参数来配置新生代内存的大小。

            如果新生代内存设置的小了,肯定是不太好,因为新生代小,可用空间就少,创建对象时一旦发现内存不足。就会触发 minorGC

            如果新生代内存设置的很大,肯定也是不好,因为新生代内存大了,那么相对而言老年代的内存肯定就小了,触发老年代的 fullGC 会更频繁,fullGCminorGC STW 的时间更长。

            Oracle 给了一个建议,即新生代内存大于堆内存 25% ,小于堆内存 50% 的比例,即堆内存的 四分之一 到 二分之一 之间。还是稍微大点好。

    5.5.3 理想容量

            新生代能容纳所有【 并发量*(请求-响应)】的数据。

            幸存区大到能够保留【当前活跃对象+需要晋升的对象】。

            晋升阈值配置得当,让长时间存活对象尽快晋升。

    1. # 调整最大晋升阈值
    2. -XX:MaxTenuringThreshold=threshold
    3. # 打印晋升的一些详细信息
    4. -XX:+PrintTenuringDistribution

    5.6 老年代调优

    5.6.1 CMS 垃圾收集器

            1、CMS 的老年代内存越大越好。

            2、先尝试不做调优,如果没有 FullGC ,就证明系统已经很不错了,否则先尝试调优新生代。

            3、如果老年代经常发生 FullGC,先观察 FullGC 时老年代内存占用,将老年代内存预设调大 1/4 ~ 1/3 。

    1. # 当老年代内存达到 percent 时就进行垃圾回收
    2. -XX:CMSInitiatingOccupancyFraction=percent

    5.7 案例

    5.7.1 FullGC 和 Minor GC 频繁

            现象:程序运行期间 FullGC MinorGC 频繁。

            分析:GC 特别频繁说明空间比较紧张。如果是新生代的空间紧张,等到业务高峰期来了,大量的对象被创建,很快就把我的新生代的空间塞满了,塞满了之后还会造成一个后果,幸存区由于空间紧张,它里面对象的晋升阈值就会降低,导致很多生存周期很短的对象也会被晋升到老年代去。此时老年代里面就存储了很多的这种生存周期很短的对象,进一步触发老年代的这种 FullGC 的频繁发生。

            解决:通过工具观察堆空间的大小,确实发现新生代的内存设置的太小了,根据之前的经验,内存优化需要先从新生代开始,即增大新生代的内存。

    5.7.2 Full GC 单次暂停时间特别长

            现象:请求高峰期发生 Full GC,单次暂停时间特别长(CMS)。

            分析:首先查看 GC 日志,看下 CMS 哪个阶段耗费的时间较长,假设是重新标记阶段耗时较长。

            解决:可以使用 -XX:+CMSScavengeBeforeRemark 参数,使得在重新标记之前先对新生代的对象做一次垃圾清理,清理完对象少了,重新标记阶段的耗时也就短了。 

    5.7.3 老年代充裕发生 Full GC

            现象:老年代充裕情况下,发生 Full GC (1.7)。

            分析:CMS 可能由于空间不足导致并发失败,或者是空间碎片较多都会导致 FullGC,但是经过排查,在 GC 日志里面并没有发现并发失败的错误提示,说明老年代的空间是充裕的。此时想到部署的 jdk 版本为 1.7,不是现在的 1.81.8 是元空间作为方法区的实现,而 1.7 以前的 jdk 采用的是永久代作为方法区的实现。在 jdk1.7 及以前的版本中,永久代的空间不足也会导致 FullGC 

            解决:增加永久代的内存即可。

  • 相关阅读:
    黑客常见攻击方法与防护方法
    unity urp 实现衣服上面片的效果
    日常遇到的数据库上的常用排查命令
    算法的时间复杂度和空间复杂度
    【CNN】SENet——将注意力机制引入通道维度
    React hooks中 useState踩坑-=--异步问题
    【动态规划】独立任务最优调度问题
    百胜杯答题系统
    面试官:说说Vue 3.0中Treeshaking特性?
    linux操作Swap
  • 原文地址:https://blog.csdn.net/xhf852963/article/details/134422127