• JVM内存调优-实践测试



    这篇文章通过一个简单的案例来向大家介绍一下几种JVM内存调优方式,希望大家可以通过实践将理论知识形成一个闭环,纸上谈兵是最没有意义的

    一、测试案例

    该接口 随机产生不同大小的对象,最大4M

    /**
         * 内存调优测试
         * @return
         */
        @GetMapping("/tuningTest")
        public String tuningTest(){
            List temp = new ArrayList();
            // 随机产生不同大小的对象,最大4MB
            int i = new Random().nextInt(8)+1;
            Byte[] bytes = new Byte[1024 * 512 * i];
            temp.add(bytes);
            return "Success";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    二、测试过程

    首先最大堆内存设置800M,初始堆大小也是800M,测试不同并发线程相同请求量的吞吐量以及相应时间

    1. 10并发线程/50000请求量 结果(吞吐量:531 平均响应时间:17)

    在这里插入图片描述
    在这里插入图片描述

    2.20并发线程/50000请求量 结果(吞吐量:566平均响应时间:39)

    在这里插入图片描述

    在这里插入图片描述

    3.40并发线程/50000请求量 结果(吞吐量:530平均响应时间:78)

    在这里插入图片描述
    在这里插入图片描述

    4.50并发线程/50000请求量 结果(吞吐量:516平均响应时间:90)

    在这里插入图片描述

    在这里插入图片描述

    从上述结果我们可以看到随着并发数量的上升,吞吐量很快就上不去了,而且响应时间却在不断上升,我们以第三次结果来看看GC 情况 (多次测试结果不一定一样,因为接口产生的对象大小随机)

    YGC : 3481次 平均时间:73.9ms FGC :70次 平均时间:3.3ms

    在这里插入图片描述

    三、优化方案

    1.增大堆内存,减少FULL GC 频率

    (我们把堆内存设置到1.2G,以上述第三种情况测试,因为上述第三种吞吐量上不去了)

    结果:(吞吐量:602 平均响应时间:79 FULL GC次数:28 )

    可以看到虽然响应时间没变但吞吐量上去了,而且FULL GC 次数大大减小了

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    2.增大年轻代,减少YGC 频率

    (堆内存800M不变,年轻代设置到600M)

    结果:(吞吐量:914平均响应时间:49 YGC 次数:1828 49ms FULL GC次数:28 )

    虽然FGC次数没变,但吞吐量达到了惊人的914 响应时间也降了下来,YGC次数几乎减少了一半
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    3.我们同时调大堆内存和年轻代

    (堆内存1200M,年轻代900M)

    结果:(吞吐量:958平均响应时间:41 YGC 次数:756 15ms FULL GC次数:23)

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    4.设置 Eden、Survivor 区比例

    在 JDK1.8 中,默认是开启 AdaptiveSizePolicy 的,则每次 GC后都会重新计算 Eden、From Survivor 和 To Survivor 区的大小,计算依据是 GC 过程中统计的 GC 时间、吞吐量、内存占用量。我们可以通过 -XX:-UseAdaptiveSizePolicy 关闭该项配置,或显示运行 -XX:SurvivorRatio=8 -XX:NewRatio=2 将 Eden、Survivor 的比例固定。

    这个比例的设置情况太多了, 我就不再演示了

    5.根据需求,设置垃圾回收器

    这个我也就不再演示了因为到了这一步都会基于场景优化了

    6.调整各种阈值参数

    不演示,这里DEMO情况过于简单,容易产生误导

    总结

    调优是一个需要基于场景、基于某种指标,大量测试得出来的一种结论,没有什么万金油的配置,实践大于一切,在复杂的业务场景下,你的理论知识终究是纸上谈兵,调优终究还是内存的利用,以及对项目的熟悉,还有业务场景的适配。

    了解对象在JVM的存活周期、了解在JVM升代的过程、了解大对象产生的场景、业务场景、并发量、GC频率、GC平均时间等等,都能给你调优带来很大帮助

    四、JVM相关知识

    1.JVM内存相关配置参数

    • 1. -XX:MaxTenuringThreshold:对象年龄计数器 升代的年龄阈值
    • 2.-XX:PetenureSizeThreshold:直接分配到老年代的对象大小阈值
    • 3. -XX:+UseAdaptiveSizePolicy:是否动态调整JVM各区域大小以及进入老年代的年龄(JDK8默认开启,建议不要随便关闭,除非你对JVM内存有了非常明确的规划)
    • 4.-XX:MaxRAMPercentage : 以容器的大小为准,按比例分配内存给JVM
    • 5. -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/ #{path}: 打印GC LOG文件到#{path}路径
    • 6.-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/#{path} :服务第一次内存溢出的时候打印Dump文件到#{path}路径
    • 7.-Xms:堆初始大小
    • 8.-Xmx:堆最大值
    • 9. -Xmn:年轻代大小
    • 10. -XX:SurvivorRatio 、 -XX:NewRatio :设置Eden、Survivor的比例

    2.GC垃圾回收器

    回收算法类型
    在这里插入图片描述

    回收器类型以及设置参数

    在这里插入图片描述

    3.GC性能衡量指标

    • 吞吐量:这里的吞吐量是指应用程序所花费的时间和系统总运行时间的比值。我们可以按照这个公式来计算 GC 的吞吐量:系统总运行时间 = 应用程序耗时 +GC 耗时。如果系统运行了 100 分钟,GC 耗时 1 分钟,则系统吞吐量为 99%。GC 的吞吐量一般不能低于95%。
    • 停顿时间:指垃圾收集器正在运行时,应用程序的暂停时间。对于串行回收器而言,停顿时间可能会比较长;而使用并发回收器,由于垃圾收集器和应用程序交替运行,程序的停顿时间就会变短,但其效率很可能不如独占垃圾收集器,系统的吞吐量也很可能会降低。
    • 垃圾回收频率:多久发生一次指垃圾回收呢?通常垃圾回收的频率越低越好,增大堆内存空间可以有效降低垃圾回收发生的频率,但同时也意味着堆积的回收对象越多,最终也会增加回收时的停顿时间。所以我们只要适当地增大堆内存空间,保证正常的垃圾回收频率即可。

    4.年轻代对象进入老年代条件

    1.正常晋升:年龄超过设置计数器的阈值

    2.大对象晋升:大小超过设置的阈值

    3.动态晋升:GC后,Survivor区域中的几个年龄对象加起来超过了Survivor区内存的一半,年龄大的晋升

    4.GC后,存活下来的对象太多,此时有新来对象Survivor区放不下,存活的老对象直接晋升老年代

    5.常用工具以及排查命令

    • 1.MAT (Eclipse Memory Analyzer )工具 :分析Dump内存文件
    • 2.GCView工具 :这可以打开GC log文件 便于分析
    • 3.top命令:查看系统CPU 以及 内存
    • 4.jstat 命令
    • 5.jmap命令
    • 6.jstack命令

    6.常用内存异常

    • 1. java heap space:堆内存溢出,FGC后依旧内存不够分配,会引起频繁FGC
    • 2.PermGen space:方法区溢出
    • 3.StackOverflowError: 栈溢出,每个请求的线程都有一个分配的栈大小,一般是死循环或者深度递归导致
    • 4. GC overhead limit exceeded:超出GC开销限制,意思是GC占用大量时间释放了很小的空间,一种内存警告,多半要发生堆内存溢出

    五、JVM系列文章

  • 相关阅读:
    Java毕设项目——人才招聘网站(java+SpringBoot+Maven+Mysql+Jsp)
    Python二级题:MOOC学校名单|关键词提取和查找
    代码随想录二刷 Day 29
    B树、B+树与磁盘读取的关系
    2023亚太杯数学建模思路 - 案例:感知机原理剖析及实现
    C++ Reference: Standard C++ Library reference: C Library: cstdio: fgets
    https协议
    【LSTM-Attention】基于长短期记忆网络融合注意力机制的多变量时间序列预测研究(Matlab代码实现)
    某网吧网络布线规划设计
    Android开发基础——UI实践
  • 原文地址:https://blog.csdn.net/weixin_44102992/article/details/126131362