前面咱们学习了整个JVM系列,最终目标的不只仅是了解JVM的基础知识,也是为了进行JVM性能调优作准备。这篇文章带领你们学习JVM性能调优的知识。java
性能调优包含多个层次,好比:架构调优、代码调优、JVM调优、数据库调优、操做系统调优等。面试
架构调优和代码调优是JVM调优的基础,其中架构调优是对系统影响最大的。数据库
性能调优基本上按照如下步骤进行:明确优化目标、发现性能瓶颈、性能调优、经过监控及数据统计工具得到数据、确认是否达到目标。缓存
遇到如下状况,就须要考虑进行JVM调优了:性能优化
JVM调优是一个手段,但并不必定全部问题均可以经过JVM进行调优解决,所以,在进行JVM调优时,咱们要遵循一些原则:服务器
经过以上原则,咱们发现,其实最有效的优化手段是架构和代码层面的优化,而JVM优化则是最后不得已的手段,也能够说是对服务器配置的最后一次“压榨”。微信
调优的最终目的都是为了令应用程序使用最小的硬件消耗来承载更大的吞吐。jvm调优主要是针对垃圾收集器的收集性能优化,令运行在虚拟机上的应用可以使用更少的内存以及延迟获取更大的吞吐量。架构
其中,任何一个属性性能的提升,几乎都是以牺牲其余属性性能的损为代价的,不可兼得。具体根据在业务中的重要性肯定。jvm
下面展现了一些JVM调优的量化目标参考实例:工具
注意:不一样应用的JVM调优量化目标是不同的。
通常状况下,JVM调优可经过如下步骤进行:
以上操做步骤中,某些步骤是须要屡次不断迭代完成的。通常是从知足程序的内存使用需求开始的,以后是时间延迟的要求,最后才是吞吐量的要求,要基于这个步骤来不断优化,每个步骤都是进行下一步的基础,不可逆行之。
JVM调优最重要的工具就是JVM参数了。先来了解一下JVM参数相关内容。
-XX 参数被称为不稳定参数,此类参数的设置很容易引发JVM 性能上的差别,使JVM存在极大的不稳定性。若是此类参数设置合理将大大提升JVM的性能及稳定性。
不稳定参数语法规则包含如下内容。
布尔类型参数值:
数字类型参数值:
字符串类型参数值:
好比如下参数示例:
-Xmx4g –Xms4g –Xmn1200m –Xss512k -XX:NewRatio=4 -XX:SurvivorRatio=8 -XX:PermSize=100m -XX:MaxPermSize=256m -XX:MaxTenuringThreshold=15
上面为Java7及之前版本的示例,在Java8中永久代的参数-XX:PermSize和-XX:MaxPermSize已经失效。这在前面章节中已经讲到。
参数解析:
新生代、老生代、永久代的参数,若是不进行指定,虚拟机会自动选择合适的值,同时也会基于系统的开销自动调整。
可调优参数:
-Xms:初始化堆内存大小,默认为物理内存的1/64(小于1GB)。
-Xmx:堆内存最大值。默认(MaxHeapFreeRatio参数能够调整)空余堆内存大于70%时,JVM会减小堆直到-Xms的最小限制。
-Xmn:新生代大小,包括Eden区与2个Survivor区。
-XX:SurvivorRatio=1:Eden区与一个Survivor区比值为1:1。
-XX:MaxDirectMemorySize=1G:直接内存。报java.lang.OutOfMemoryError: Direct buffer memory异常能够上调这个值。
-XX:+DisableExplicitGC:禁止运行期显式地调用System.gc()来触发fulll GC。
注意: Java RMI的定时GC触发机制可经过配置-Dsun.rmi.dgc.server.gcInterval=86400来控制触发的时间。
-XX:CMSInitiatingOccupancyFraction=60:老年代内存回收阈值,默认值为68。
-XX:ConcGCThreads=4:CMS垃圾回收器并行线程线,推荐值为CPU核心数。
-XX:ParallelGCThreads=8:新生代并行收集器的线程数。
-XX:MaxTenuringThreshold=10:设置垃圾最大年龄。若是设置为0的话,则年轻代对象不通过Survivor区,直接进入年老代。对于年老代比较多的应用,能够提升效率。若是将此值设置为一个较大值,则年轻代对象会在Survivor区进行屡次复制,这样能够增长对象再年轻代的存活时间,增长在年轻代即被回收的概论。
-XX:CMSFullGCsBeforeCompaction=4:指定进行多少次fullGC以后,进行tenured区 内存空间压缩。
-XX:CMSMaxAbortablePrecleanTime=500:当abortable-preclean预清理阶段执行达到这个时间时就会结束。
在设置的时候,若是关注性能开销的话,应尽可能把永久代的初始值与最大值设置为同一值,由于永久代的大小调整须要进行FullGC才能实现。
当JVM运行稳定以后,触发了FullGC咱们通常会拿到以下信息:
以上gc日志中,在发生fullGC之时,整个应用的堆占用以及GC时间。为了更加精确需屡次收集,计算平均值。或者是采用耗时最长的一次FullGC来进行估算。上图中,老年代空间占用在93168kb(约93MB),以此定为老年代空间的活跃数据。则其余堆空间的分配,基于如下规则来进行。
基于以上规则,则对参数定义以下:
java -Xms373m -Xmx373m -Xmn140m -XX:PermSize=5m -XX:MaxPermSize=5m
对延迟性优化,首先须要了解延迟性需求及可调优的指标有哪些。
其中,平均停滞时间和最大停顿时间,对用户体验最为重要。对于上面的指标,相关数据采集包括:MinorGC的持续时间、统计MinorGC的次数、FullGC的最差持续时间、最差状况下,FullGC的频率。
如上图,Minor GC的平均持续时间0.069秒,MinorGC的频率为0.389秒一次。
新生代空间越大,Minor GC的GC时间越长,频率越低。若是想减小其持续时长,就须要减小其空间大小。若是想减少其频率,就须要加大其空间大小。
这里以减小了新生代空间10%的大小,来减少延迟时间。在此过程当中,应该保持老年代和持代的大小不变化。调优后的参数以下变化:
java -Xms359m -Xmx359m -Xmn126m -XX:PermSize=5m -XX:MaxPermSize=5m
吞吐量调优主要是基于应用程序的吞吐量要求而来的,应用程序应该有一个综合的吞吐指标,这个指标基于整个应用的需求和测试而衍生出来的。
评估当前吞吐量和目标差距是否巨大,若是在20%左右,能够修改参数,加大内存,再次从头调试,若是巨大就须要从整个应用层面来考虑,设计以及目标是否一致了,从新评估吞吐目标。
对于垃圾收集器来讲,提高吞吐量的性能调优的目标就是尽量避免或者不多发生FullGC或者Stop-The-World压缩式垃圾收集(CMS),由于这两种方式都会形成应用程序吞吐下降。尽可能在MinorGC 阶段回收更多的对象,避免对象提高过快到老年代。
借助GCViewer日志分析工具,能够很是直观地分析出待调优势。可从如下几方面来分析:
Memory,分析Totalheap、Tenuredheap、Youngheap内存占用率及其余指标,理论上内存占用率越小越好;
Pause,分析Gc pause、Fullgc pause、Total pause三个大项中各指标,理论上GC次数越少越好,GC时长越小越好;
原文连接:《JVM性能调优详解》
本文参考:
(1)http://www.javashuo.com/article/p-wnvshwvs-ee.html
(2)http://www.javashuo.com/article/p-qvijjyrm-gz.html
《面试官》系列文章: