案例1 survivor区太小,每次Minor GC存活的对象进入老年代,导致老年代可用空间不足,经常发生FULL GC,导致系统变慢

  • 案例问题描述

    • 有一个数据计算系统,从mysql和其他数据源提取数据到jvm进行计算

    • 该系统每分钟大约执行500次提取数据和计算

    • 该系统是分布式的,生产环境部署了多台机器,每台机器大约每分钟执行100次数据的提取和计算,每次会提取1万条数据到内存进行计算

    • 每台机器配置是4核8G,JVM内存给了4G,新生代和老年代分别是1.5G内存空间

    • 每条数据大约20个字段,一条数据就是1KB大小,计算一万条数据就是10M大小

    • jvm新生代按照8:1:1分配空间,Eden区是1.2G,每个survivor区是100M

    • 每执行一次任务,Eden区就会分配10M左右的对象,每分钟执行100次,那么一分钟左右,Eden区就会装满对象

    • Eden区占满,会触发Minor GC;Minor GC之前会检查老年代可用空间大小,此时老年代大小1.5G,大于1.2G,就算Eden区的对象全部存活,老年代也放得下,所以直接进行Minor GC

    • 每个jvm每分钟要跑100次任务,每次任务一万条数据,每条数据1KB,那么每次任务数据就是10M大小;一分钟结尾的时候,Eden区被占满,要进行Minor GC,此时80个任务已经跑完,20个任务还在跑,此时200M对象是存活的,不能被回收,有1GB对象是可以被回收的

    • 存活对象200M,survivor区大小是100M,放不下,存活对象直接放入老年代,Eden区清空

    • 每隔一分钟进行一次Minor GC垃圾回收,放入老年代对象有200M,两分钟以后,老年代放入400M,剩余1.1G,再发生Minor GC时,年轻代对象总大小1.2G大于老年代可用空间1.1G,此时需要进行参数-XX:-HandlePromotionFailure判断,如果设置了该参数,看老年代可用空间是否大于历次Minor GC过后进入老年代的对象的平均大小;1.1G大于200M,直接进行Minor GC,又有200M对象进入老年代

    • 七分钟过后,老年代对象变成了1.4G,可用空间还剩100M

    • 第八分钟运行结束时,新生代又满了,执行Minor GC之前检查,发现老年代可用空间100M,小于存活对象200M大小,直接进行一次FULL GC,回收全部可以回收的1.4G对象

    • 总的来说,没7-8分钟就要进行一次FULL GC,频率很高,导致系统很慢

  • 解决方案

    • 增大survivor区大小,使survivor区大于每次Minor GC后存活对象,那么存活对象会放入survivor区,不会进入老年代,避免FULL GC
    • 堆内存一共3G,新生代分配2GB,老年代分配1GB
    • 这样,每个survivor区是200M左右,放得下Minor GC后存活的对象
    • 另外,如果为了防止动态年龄判断,把一些对象直接放入老年代,可修改-XX:SurvivorRatio=8参数,调整Eden区和Survior区的比例,增大survivor区


案例2 电商大促jvm参数设置调优

  • 案例问题描述及其解决方案

    • 10分钟50万订单,每秒1000个下单请求(1000QPS),3台机器来负担这些请求,每台机器负责300个请求/秒;每台机器处理100-300请求/秒是正常的
    • 每个订单按1KB算,300个订单是300KB;算上其他连带对象,一般对单个对象开销扩大10-20倍
    • 除了创建订单,还有其他连带操作,还需再扩大10倍
    • 每秒钟有 300KB*20*10 = 60M 的内存开销;但是一秒过后,可以认为这60mb的对象就是垃圾了,因为300个订单处理完了,所有相关对象都失去了引用,可以回收的状态
    • 机器8G内存,4G分给jvm,3G分给堆(新生代和老年代分别1.5G),每个线程的Java虚拟机栈有1M,JVM大约几百线程,也就是几百兆,元空间(方法区)256M。以上总和大约为4G
    • 每秒处理300个订单,都会占据新生代60M内存空间,新生代1.5G大约25秒就会被占满
    • 刚开始,老年代可用内存空间大于新生代对象大小,所以Minor GC直接运行,除了最近一秒的订单请求还在处理,大部分订单早就处理完了,所以此时可能存活对象就100MB左右
    • -XX:SurvivorRatio参数默认值是8,Eden区和Survivor区比例是8:1:1,Eden区1.2G,每个Survivor区大约是150M
    • Eden区1.2G大约20秒就会被对象塞满,就要进行Minor GC;清空Eden区,存活对象100M进入S1区(Survivor区)
    • 再运行20s,Eden区再次被占满,回收Eden区和S1区的对象,存活对象放入S2区,JVM参数设置如下-Xms3072M -Xmx3072M -Xmn1536M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8
    • Survivor区150M,存活对象预估100M,但很可能突破150M,导致Minor GC存活的对象Survivor区放不下,频繁进入老年代
    • 即使Minor GC存活的对象小于150M,由于是同一批对象,大于Survivor区的百分之50,动态年龄判断,存活对象也会进入老年代,这个jvm参数设置明显Survivor区空间不足
    • 对象尽量留在新生代,老年代没必要设置的太大,把新生代调整为2G,老年代调整为1G,Survivor区变为200M,大大降低了Minor GC存活的对象进入老年代的概率
    • 其实对任何系统,首先类似上文的内存使用模型预估以及合理的分配内存,尽量让每次Minor GC后的对象都留在Survivor里,不要进入老年代,这是你首先要进行优化的一个地方
    • 还有一个问题,新生代存活对象躲过多少次Minor GC进入老年代?-XX:MaxTenuringThreshold参数默认是15次。设置这个参数必须结合系统的运行模型来说,如果躲过15次Minor GC都几分钟了,一个对象几分钟不被回收,说明肯定是@Service@Controller核心业务逻辑组件,应该放入老年代,甚至这个参数设置成5次,1分钟不被回收的对象尽快进入老年代,不占用新生代空间
    • 多大的大对象直接进入老年代?-XX:PretenureSizeThreshold=1M
  • 总结
    • 每秒占用多少内存?
    • 多长时间触发一次Minor GC?
    • 一般Minor GC后有多少存活对象?
    • Survivor能放的下吗?
    • 会不会频繁因为Survivor放不下导致对象进入老年代?
    • 会不会因动态年龄判断规则进入老年代?


本文参考救火队长jvm专栏

jvm优化案例的更多相关文章

  1. Spark集群之yarn提交作业优化案例

    Spark集群之yarn提交作业优化案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.启动Hadoop集群 1>.自定义批量管理脚本 [yinzhengjie@s101 ...

  2. 数据库优化案例——————某市中心医院HIS系统

    记得在自己学习数据库知识的时候特别喜欢看案例,因为优化的手段是容易掌握的,但是整体的优化思想是很难学会的.这也是为什么自己特别喜欢看案例,今天也开始分享自己做的优化案例. 最近一直很忙,博客产出也少的 ...

  3. JVM优化

    1.堆大小设置 JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:64 ...

  4. JVM 优化问题

    jvm 优化问题 JVM堆内存分为2块:Permanent Space 和 Heap Space. Permanent 即 持久代(Permanent Generation),主要存放的是Java类定 ...

  5. mysql优化案例

    MySQL优化案例 Mysql5.1大表分区效率测试 Mysql5.1大表分区效率测试MySQL | add at 2009-03-27 12:29:31 by PConline | view:60, ...

  6. SQL 优化案例 1

    create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...

  7. 老李案例分享:Weblogic性能优化案例

    老李案例分享:Weblogic性能优化案例 POPTEST的测试技术交流qq群:450192312 网站应用首页大小在130K左右,在之前的测试过程中,其百用户并发的平均响应能力在6.5秒,性能优化后 ...

  8. Hive优化案例

    1.Hadoop计算框架的特点 数据量大不是问题,数据倾斜是个问题. jobs数比较多的作业效率相对比较低,比如即使有几百万的表,如果多次关联多次汇总,产生十几个jobs,耗时很长.原因是map re ...

  9. 数据库优化案例——————某知名零售企业ERP系统

    写在前面 记得在自己学习数据库知识的时候特别喜欢看案例,因为优化的手段是容易掌握的,但是整体的优化思想是很难学会的.这也是为什么自己特别喜欢看案例,今天也分享自己做的优化案例. 之前分享过OA系统.H ...

随机推荐

  1. 【Flutter 实战】17篇动画系列文章带你走进自定义动画

    老孟导读:Flutter 动画系列文章分为三部分:基础原理和核心概念.系统动画组件.8篇自定义动画案例,共17篇. 动画核心概念 在开发App的过程中,自定义动画必不可少,Flutter 中想要自定义 ...

  2. Linux下命令设置别名--alias(同实用于mac)

    最近在搞appium自动化脚本编写,过程中经常会使用 uiautomatorviewer这个工具查看UI布局和元素,但是不得不说这个单词太长了.. 如何快速使用,有三个小技巧,分别是: 1.设置好改工 ...

  3. JVM内存区域与垃圾回收

    1.JAVA内存区域与内存溢出 1.1.概述 Java中JVM提供了内存管理机制,Java虚拟机在执行Java程序的过程中会把内分分为不同的数据区,如图: 1.2.程序计数器 程序计数器是当前线程所执 ...

  4. 【原创】如何优雅的转换Bean对象

    背景 我们的故事要从一个风和日丽的下午开始说起! 这天,外包韩在位置上写代码-外包韩根据如下定义 PO(persistant object):持久化对象,可以看成是与数据库中的表相映射的 java 对 ...

  5. Azure Blob (三)参数设置说明

    一,引言 上一篇将 Azure Blob 存储的时候,有使用到一个 .NET  Core Web 项目,通过代码的方式进行操作 Azure Blob 的数据,接着上一篇的内容,今天继续看一下代码,具体 ...

  6. Python之 最全 Conda、pip 管理环境和安装包、更换源、解决HttpError等一些列问题

    在Anaconda中conda可以理解为一个工具,也是一个可执行命令,其核心功能是环境管理与包管理.所以对虚拟环境进行创建.删除等操作需要使用conda命令. conda install 和 pip ...

  7. Q200510-02: 重复的DNA序列 程序解法

    问题:  重复的DNA序列 所有 DNA 都由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”.在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助. 编 ...

  8. AI研讨会直播:《人工智能开发前沿》实战系列公开课第1期

    报名链接:https://www.slidestalk.com/m/276 活动背景 业务需求.数据.算法.算力等因素,决定人工智能技术走向产业落地面临各种挑战.博客园联合示说网以及产业内人工智能技术 ...

  9. Require.js中的路径在IDEA中的最佳实践

    本文主要讲述require.js在IDEA中路径智能感知的办法和探索中遇到的问题. 测试使用的目录结构:一种典型的thinkphp 6的目录结构,如下图. 现在我通过在 vue-a.js 中运用不同的 ...

  10. 在express中使用ES7装饰器构建路由

    在Java的Spring框架中,我们经常会看到类似于@Controller这样的注解,这类代码能够极大的提高我们代码的可读性和复用性.而在Javascript的ES7提案中,有一种新的语法叫做deco ...