栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JVM调优经历

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JVM调优经历

记一次JVM调优经历
  • 一、JVM内存溢出问题
  • 二、JVM调优步骤
    • 1、增大JVM初始堆内存
    • 2、增大堆内存
    • 3、调整新生代与老年代比例
  • 三、其他JVM调优知识
    • 1、Full GC
    • 2、新生代对象进入老年代条件

一、JVM内存溢出问题
  1. 程序报错
    10:06:01 [WARN ] i.n.util.concurrent.DefaultPromise java.lang.OutOfMemoryError: Java heap space

  2. 出现场景
    程序导出数据库中数据,导出5W数据,每次查询1000.
    for循环中创建大量对象,导致内存溢出,怀疑短时间内创建大量对象,内存回收不及时导致堆溢出。

  3. 预测需要内存大小

    System.setProperty("java.vm.name","Java HotSpot(TM) ");
    System.out.println(ObjectSizeCalculator.getObjectSize(dataList));
    

    可以得出对象占用大小,
    单次循环内 1000条数据占用内存 2,345,568 。 约 2.3M。

    需要导出5w条数据,循环50次。 每次循环结束,创建的对象都会失效回收,最差情况需要最大内存 115M

  4. 查看机器中Java程序堆内存的默认初始大小和最大大小

    -Xmx 最大堆内存的默认值为当前机器最大内存的 1/4
    -Xms 初始堆内存的默认值为当前机器最大内存的 1/64

    在Windows里:
    java -XX:+PrintFlagsFinal -version | findstr /i "HeapSize PermSize ThreadStackSize"
    在Linux里:
    java -XX:+PrintFlagsFinal -version | grep -iE 'HeapSize|PermSize|ThreadStackSize'
    

    可以看出最大堆内存为503M,初始堆内存为33M,我们的机器内存为2G,符合上述比例。

二、JVM调优步骤 1、增大JVM初始堆内存
-Xms128 -Xmx512m

报错:Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

原因:

执行垃圾收集的时间比例太大,有效的运算量太小。默认情况下,如果GC花费的时间超过 98%,并且GC 回收的内存少于 2%,JVM 就会抛出这个错误。
假如不抛出 GC overhead limit 错误会发生什么情况呢? 那就是 GC 清理的这么点内存很快会再次填满,迫使 GC 再次执行。这样就形成恶性循环,CPU 使用率一直是 100%,而 GC 却没有任何成果。系统用户就会看到系统卡死。以前只需要几毫秒的操作,现在需要好几分钟才能完成。

分析:每次for循环结束,都会GC,但是每次回收的内存很少,频繁GC导致CPU利用率过高报错。

解决办法:

  • 检查程序是否有循环,生成大量对象,优化代码
  • -XX:-UseGCOverheadLimit 禁用这个检查,只是错误信息延后,替换成 java.lang.OutOfMemoryError: Java heap space
  • 增大堆内存
2、增大堆内存
-Xms256m -Xmx2560m

测试正常,但服务发生多次 Full GC,严重影响性能。

初步判断为老年代空间不足引发Full GC。
由于服务主要是循环创建大量对象导致内存问题,每次循环后创建的对象都将失效,部分对象会进入老年代导致老年代空间不足,触发Full GC

解决方法:

减少Full GC,增加Minor GC,调整新生代与老年代比例,增大新生代内存。

3、调整新生代与老年代比例

设置 -XX:NewRatio, 默认为2,代表新生代与老年代内存比为1:2,新生代占1/3

-XX:NewRatio=1

再次测试,发现Full GC次数大幅减少

三、其他JVM调优知识
  • Minor GC :清理新生代,Minor GC是最频繁触发的GC,速度也最快的;
  • Major GC :清理老年代,Major GC比Minor GC慢十倍以上,单独触发Major GC只有CMS和G1有这个能力,因为cms和G1处理老年代不需要触发full gc,其他的老年代回收器回收老年代需要触发full gc。
  • Full GC: 清理整个堆空间,包括新生代、永久代和老年代,它会启动老年代收集器和新生代收集器一起工作,全程Stop The World,尽量避免Full GC
1、Full GC

Full GC会回收整个堆的内存,包含老年代,新生代,metaspace等,GC的全过程中所有用户线程都是处于暂停的状态。
触发条件:

  • 老年代空间不足
  • 永久代/metaspace内存空间不足
  • 调用System.gc()会建议系统调用full gc
2、新生代对象进入老年代条件
  1. 根据对象年龄,每熬过一次GC,年龄+1,达到阈值后进入老年代。通过 -XX:MaxTenuringThreshold设置阈值
  2. 大对象直接进入老年代,通过 -XX:PretenureSizeThreshold设置
  3. 动态年龄判断
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1035737.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号