通过之前大量的案例和工具的介绍,相信大家对于JVM优化有了一定的了解和熟悉,接下来我们将整个JVM性能优化的步骤做一个总结。
1)开发完上线前的JVM参数设置
开发完毕一个项目后,如果不做JVM参数设置而是采用默认的JVM参数直接部署上线,那一定是不靠谱的!出了问题再去观察分析解决,调整JVM参数,这是拿公司资产开玩笑。但是很多公司也没有所谓的JVM参数模板。
那么我们应该如何做呢?
首先,做合理预估
针对该系统的每个核心接口估算每秒多少次请求,每次请求会创建多少个对象,每个对象大概有多大,每秒钟占据分配多少内存空间。
- 接着估算Eden区大概多长时间会占满。
- 从而估算出来多久会发生一个Minor GC,以及有多少存活对象,有多少对象会进入老年代,老年代增长的速率是多少,预计多久触发一次Full GC。
通过以上的估算分析,就可以针对当前的项目系统做一个初步的合理估算,给出预计的内存分配,堆内存(Eden和Survivor区的分配)以及老年代的大小分配。尽量让每次Minor GC后存活下的对象远小于Survivor区域,避免对象频繁进入老年代从而触发Full GC。
比较理想的状态就是:
系统偶尔发生一次Mionr GC,每次GC后没有对象进入老年代,能进入老年代的对象只有长期持有存活,经历15次Minor GC后自然进入老年代的对象,老年代几乎不发生GC,新生代也就最多几分钟一次,每次耗时几毫秒。
2)压测之后合理调整JVM参数
每当系统上线前,都必须经历一次压测,在压测模式下模拟系统在线上压力的环境下运行的状态,同时我们可以通过jstat工具,定时打印输出JVM压测下的内存运行模型,重点观察以下几个指标:
- Eden区的对象增长速率
- Minor GC的频繁以及耗时
- Minor GC后的存活对象大小
- 老年代的对象增长速率
- Full GC的频率以及耗时
通过压测时分析模拟出来的内存数据,进而进一步对JVM参数进行优化,内存合理分配,尽量做到只触发Minor GC。
3)线上系统的监控和优化
系统正式上线后,肯定要有内存的监控!一般的简单快速做法,可以考虑直接使用 jstat工具,输出写入到指定的文件,每天定时查看。
比较高级一点的做法可以考虑直接采用 Zabbix(一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案)或者 Open-Falcon(小米运维部门开源出来的互联网企业级监控系统,目前包括小米、金山云、美团、京东金融、赶集网等都在使用Open-Falcon)之类的工具来监控机器和JVM的运行,一旦频繁Full GC就触发报警机制。
优化的核心还是通过工具分析出来Full GC频繁触发的关键因素,找出核心问题所在,从而优化对应JVM参数,减少Full GC的触发频率。(可以多参考熟悉之前优化的案例,自己多动手熟练下)
4)线上频繁FullGC的几种表现
常见表现不外乎以下三种:
- 频繁Full GC报警
- 机器CPU负载过高
- 系统无法处理请求或处理过慢
5)频繁FullGC的几种常见原因
常见的几种原因归纳为以下几种:
- 系统承载高并发请求,处理数据量过大,导致Minor GC频繁,每次GC后存活对象过多,Survivor区域过小,进入老年代对象过多过于频繁,从而导致Full GC频繁
- 大促或高峰时期,单次加载数据量过大,造成大对象直接进入老年代,从而频繁触发Full GC
- 内存泄露,莫名其妙产生大量对象无法回收,长期持有,并且一直占据在老年代了,吃空间,导致频繁FullGC
- Metspace(永久代)加载过多触发Full GC
- 手动调用System.GC
针对第一种情况,擅于使用jstat利器分析核心问题,调整内存大小,增大Surviror区域。
针对第二种和第三种情况,采取 dump堆内存快照,利用MAT工具分析大对象到底是谁
6)一个统一的JVM参数模板
之前已经给大家分享过公司级别的JVM参数模板,每一个团队都应该有一个标准的JVM参数模板,统一调试和开发,由leader进行统一优化和调整。
这里再贴下给大家做个参考:(重点是结合自己的系统和实际物理机器,切忌直接复制使用)
-Xms4096M
-Xmx4096M
-Xmn3072M
-Xss1M
-XX:PermSize=256M
-XX:MaxPermSize=256M
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=92
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSParallelInitialMarkEnabled
-XX:+CMSScavengeBeforeRemark
小结
通过之前的大量案例以及JVM性能优化的讲解我们最后总结提炼如下:
- 开发完上线前的JVM参数设置
- 压测之后合理调整JVM参数
- 线上系统的监控和优化
- 线上频繁FullGC的几种表现
- 频繁FullGC的几种常见原因
- 一个统一的JVM参数模板