1. JVM调优的目标
使用较小的内存占用来获得较高的吞吐量或者较低的延迟。
程序在上线前的测试或运行中有时会出现一些大大小小的JVM问题,比如cpu load过高、请求延迟、tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高,每次垃圾收集清理掉的垃圾数据越来越少)、内存溢出导致系统崩溃,因此需要对JVM进行调优,使得程序在正常运行的前提下,获得更高的用户体验和运行效率。
其实jvm调优主要是减少full gc 的次数,减少stw
2. 重要指标
- 内存占用:程序正常运行需要的内存大小
- 延迟:由于垃圾收集而引起的程序停顿时间
- 吞吐量:用户程序运行时间占用户程序和垃圾收集占用总时间的比值
3. 调优工具
- 系统运行日志,程序打印的log
- 堆栈错误信息
- java.lang.OutOfMemoryError: Java heap space: 堆内存溢出
- java.lang.StackOverflowError:栈内存溢出
- java.lang.OutOfMemoryError: PermGen space:方法区溢出
- GC日志:程序启动时增加参数
-XX:+PrintGCDetails -Xloggc:/data/jvm/gc.log
可以在程序运行时把gc的详细过程记录下来,或者直接配置
-verbose:gc参数把gc日志打印到控制台,通过记录的gc日志可以分析每块内存区域gc的频率、时间等,从而发现问题,进行有针对性的优化
4. JVM调优经验
JVM配置方面,一般情况可以先用默认配置(基本的一些初始参数可以保证一般的应用跑的比较稳定了),在测试中根据系统运行状况(会话并发情况、会话时间等),结合gc日志、内存监控、使用的垃圾收集器等进行合理的调整,当老年代内存过小时可能引起频繁Full GC,当内存过大时Full GC时间会特别长。
那么JVM的配置比如新生代、老年代应该配置多大最合适呢?答案是不一定,调优就是找答案的过程,物理内存一定的情况下,新生代设置越大,老年代就越小,Full GC频率就越高,但Full GC时间越短;相反新生代设置越小,老年代就越大,Full GC频率就越低,但每次Full GC消耗的时间越大。建议如下:
- -Xms和-Xmx的值设置成相等,堆大小默认为-Xms指定的大小,默认空闲堆内存小于40%时,JVM会扩大堆到-Xmx指定的大小;空闲堆内存大于70%时,JVM会减小堆到-Xms指定的大小。如果在Full GC后满足不了内存需求会动态调整,这个阶段比较耗费资源。
- 新生代尽量设置大一些,让对象在新生代多存活一段时间,每次Minor GC 都要尽可能多的收集垃圾对象,防止或延迟对象进入老年代的机会,以减少应用程序发生Full GC的频率。
- 老年代如果使用CMS收集器,新生代可以不用太大,因为CMS的并行收集速度也很快,收集过程比较耗时的并发标记和并发清除阶段都可以与用户线程并发执行。
- 方法区大小的设置,1.6之前的需要考虑系统运行时动态增加的常量、静态变量等,1.7只要差不多能装下启动时和后期动态加载的类信息就行。
代码实现方面,性能出现问题比如程序等待、内存泄漏除了JVM配置可能存在问题,代码实现上也有很大关系:
- 避免创建过大的对象及数组:过大的对象或数组在新生代没有足够空间容纳时会直接进入老年代,如果是短命的大对象,会提前出发Full GC。
- 避免同时加载大量数据,如一次从数据库中取出大量数据,或者一次从Excel中读取大量记录,可以分批读取,用完尽快清空引用。
- 当集合中有对象的引用,这些对象使用完之后要尽快把集合中的引用清空,这些无用对象尽快回收避免进入老年代。
- 可以在合适的场景(如实现缓存)采用软引用、弱引用,比如用软引用来为ObjectA分配实例:SoftReference objectA=new SoftReference(); 在发生内存溢出前,会将objectA列入回收范围进行二次回收,如果这次回收还没有足够内存,才会抛出内存溢出的异常。 避免产生死循环,产生死循环后,循环体内可能重复产生大量实例,导致内存空间被迅速占满。
- 尽量避免长时间等待外部资源(数据库、网络、设备资源等)的情况,缩小对象的生命周期,避免进入老年代,如果不能及时返回结果可以适当采用异步处理的方式等。
- 案例
- JVM服务问题排查 blog.csdn.net/jacin1/arti…
- 让人难以忘怀的排查频繁Full GC过程 caogen81.iteye.com/blog/151334…
- 线上FullGC频繁的排查 blog.csdn.net/wilsonpeng3…
- 【JVM】线上应用故障排查 www.cnblogs.com/Dhouse/p/78…
- 一次JVM中FullGC问题排查过程 iamzhongyong.iteye.com/blog/183026…
- JVM内存溢出导致的CPU过高问题排查案例 blog.csdn.net/nielinqi520…
- 一个java内存泄漏的排查案例 blog.csdn.net/aasgis6u/ar…