1调优层次
性能调优包含多个层次,比如:架构调优、代码调优、JVM调优、数据库调优、操作系统调优等。架构调优和代码调优是JVM调优的基础,其中架构调优是对系统影响最大的。
2调优指标
吞吐量:运行用户代码的时间占总运行时间的行例(总运行时间=程序的运行时间+内存回收的时间);
暂停时间:执行垃圾收集时,程序的工作线程被暂停的时间;
内存占用:java堆区所占的内存大小;
这三者共同构成一个“不可能三角”。三者总体的表现会随着技术进步而越来越好。一款优秀的收集器通常最多同时满足其中的两项。
简单来说,主要抓住两点:
吞吐量吞吐量优先,意味着在单位时间内,STW的时间最短
暂停时间暂停时间优先,意味这尽可能让单次STW的时间最短
在设计(或使用)GC算法时,必须确定我们的目标:一个GC算法只可能针对两个目标之一(即只专注于较大吞吐量或最小暂停时间),或尝试找一个二者的折衷。
现在标准,在最大吞吐量优先的情况下,降低停顿时间。
3JVM调优原则
3.1优先原则
优先架构调优和代码调优,JVM优化是不得已的手段,大多数的Java应用不需要进行JVM优化
3.2堆设置
参数-Xms和-Xmx,通常设置为相同的值,避免运行时要不断扩展JVM内存,建议扩大至3-4倍FullGC后的老年代空间占用。
3.3年轻代设置
参数-Xmn,1-1.5倍FullGC之后的老年代空间占用。
避免新生代设置过小,当新生代设置过小时,会带来两个问题:一是minorGC次数频繁,二是可能导致minorGC对象直接进老年代。当老年代内存不足时,会触发FullGC。避免新生代设置过大,当新生代设置过大时,会带来两个问题:一是老年代变小,可能导致FullGC频繁执行;二是minorGC执行回收的时间大幅度增加。
3.4老年代设置
注重低延迟的应用
老年代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数
如果堆设置偏小,可能会造成内存碎片、高回收频率以及应用暂停
如果堆设置偏大,则需要较长的收集时间
吞吐量优先的应用一般吞吐量优先的应用都有一个较大的年轻代和一个较小的老年代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而老年代尽可能存放长期存活对象
3.5方法区设置
基于jdk1.7版本,永久代:参数-XX:PermSize和-XX:MaxPermSize;基于jdk1.8版本,元空间:参数-XX:MetaspaceSize和-XX:MaxMetaspaceSize;通常设置为相同的值,避免运行时要不断扩展,建议扩大至1.2-1.5倍FullGc后的永久带空间占用。
3.6GC设置
3.6.1GC发展阶段
SerialParallel(并行)CMS(并发)G1ZGC截至jdk1.8,一共有7款不同垃圾收集器。每一款不同的垃圾收集器都有不同的特点,在具体使用的时候,需要根据具体的情况选择不同的垃圾回收器
3.6.2G1的适用场景
面向服务端应用,针对具有大内存、多处理器的机器。(在普通大小的堆里表现并不惊喜)
最主要的应用是需要低GC延迟并具有大堆的应用程序提供解决方案(G1通过每次只清理一部分而不是全部Region的增量式清理来保证每次GC停顿时间不会过长)
在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒
用来替换掉JDK1.5中的CMS收集器,以下情况,使用G1可能比CMS好
超过50%的java堆被活动数据占用
对象分配频率或年代提升频率变化很大
GC停顿时间过长(大于0.5至1秒)
从经验上来说,整体而言:
小内存应用上,CMS大概率会优于G1;
大内存应用上,G1则很可能更胜一筹。这个临界点大概是在6~8G之间(经验值)
3.6.3其他收集器适用场景
如果你想要最小化地使用内存和并行开销,请选择SerialOld(老年代)+Serial(年轻代)
如果你想要最大化应用程序的吞吐量,请选择ParallelOld(老年代)+Parallel(年轻代)
如果你想要最小化GC的中断或停顿时间,请选择CMS(老年代)+ParNew(年轻代)
4JVM调优步骤
4.1监控分析
分析GC日志及dump文件,判断是否需要优化,确定瓶颈问题点。
4.1.1如何生成GC日志
常用参数部分会详细讲解如何生成GC日志
4.1.2如何产生dump文件
4.1.2.1JVM的配置文件中配置
JVM启动时增加两个参数:
#出现OOME时生成堆dump:-XX:+HeapDumpOnOutOfMemoryError#生成堆文件