明白自己“JVM调优”在整个系统调优的位置。
优先原则:
优先架构调优和代码调优,JVM是不得已的手段,在既定的架构和代码逻辑下,JVM调整效果有限。就像“一个人本身长的不高,穿的鞋子衣服再修身增高,能高到哪里去”,架构和编码就是你的骨骼, JVM调优就是你的增高鞋垫。
触发点:为了解决“并发上不去”,“CPU过高”,“内存溢出”等问题开始调优。
调优不是优化,调试说明要找到一个黄金分割点,而不是解决某个问题,那是修复BUG。既然是调试,那么在哪几个指标中间调就需要明确。
指标项:
这三者共同构成一个“不可能三角”。三者总体的表现会随着技术进步而越来越好。一款优秀的收集器通常最多同时满足其中的两项。
相互影响:扩大堆内存,会增加“暂停时间”,但会降低GC次数。明显的暂停会对通途量有严重的影响,如果内存没法扩展,在最大吞吐量优先的情况下,降低停顿时间。
需要明白JVM有哪些开关,已经这些开关调整会产生的影响。
FullGC 后老年代依然存在的对象,对应代码中:static或者存储的缓存数据。
-Xms和-Xmx 堆内存初始化和最大的值:通常设置为相同的值,避免运行时要不断扩展JVM内存
建议:扩大至3-4倍“FullGC后的老年代空间占用”
参数-Xmn,1-1.5倍FullGC之后的老年代空间占用
避免新生代设置过小,当新生代设置过小时,会带来两个问题:
1. minor GC次数频繁
2.导致minor GC对象直接进老年代。当老年代内存不足时,会触发Full GC
避免新生代设置过大,当新生代设置过大时,会带来两个问题:
1.老年代变小,可能导致Full GC频繁执行
2. minor GC 执行回收的时间大幅度增加
注重低延迟的应用
老年代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数
如果堆设置偏小,可能会造成内存碎片、高回收频率以及应用暂停
如果堆设置偏大,则需要较长的收集时间
基于jdk1.7版本,永久代:参数-XX:PermSize和-XX:MaxPermSize
基于jdk1.8版本,元空间:参数 -XX:MetaspaceSize和-XX:MaxMetaspaceSize
通常设置为相同的值,避免运行时要不断扩展
建议扩大至1.2-1.5倍“FullGc后的永久带空间占用”
这点体会不是很深。
SerialParallel(并行) CMS(并发) G1ZGC 截至jdk1.8 ,一共有7款不同垃圾收集器。每一款不同的垃圾收集器都有不同的特点,在具体使用的时候,需要根据具体的情况选择不同的垃圾回收器
面向服务端应用,针对具有大内存、多处理器的机器。(在普通大小的堆里表现并不惊喜)
最主要的应用是需要低GC延迟并具有大堆的应用程序提供解决方案(G1通过每次只清理一部分而不是全部Region的增量式清理来保证每次GC停顿时间不会过长)
在堆大小约6GB或更大时,可预测的暂停时间可以低于0.5秒
用来替换掉JDK1.5中的CMS收集器,以下情况,使用G1可能比CMS好
从经验上来说,整体而言:
小内存应用上,CMS大概率会优于 G1;
大内存应用上,G1则很可能更胜一筹。 这个临界点大概是在 6~8G 之间(经验值)
如果你想要最小化地使用内存和并行开销,请选择Serial Old(老年代) + Serial(年轻代)
如果你想要最大化应用程序的吞吐量,请选择Parallel Old(老年代) + Parallel(年轻代)
如果你想要最小化GC的中断或停顿时间,请选择CMS(老年代) + ParNew(年轻代)
异常或者预警现象:
1. CPU,内存占用率超过80%,后者更高
2. MinorGC,FullGC 频繁,或者停顿过长(超过1秒)
3. 日志打印异常
4. 系统运行一段时间后卡顿或者吞吐量下降
5. 系统启动后就占用大量内存
调优的最终目的都是为了应用程序使用最小的硬件消耗来承载更大的吞吐量或者低延迟。 jvm调优主要是针对垃圾收集器的收集性能优化,减少GC的频率和Full GC的次数,令运行在虚拟机上的应用能够使用更少的内存、高吞吐量、低延迟。
下面列举一些JVM调优的量化目标参考实例
注意:不同应用的JVM调优量化目标是不一样的。
调优先后:满足程序的内存使用需求 ==》 解决时间延迟 ==》 通途量。每一个步骤都是进行下一步的基础,不可逆行之。
1. 先找一个服务在本地调试,找到明显的问题
2. 找一个线上实例进行验证
3. 最后推广到机器,并进行后续跟踪
jps:JVM Process Status Tool
jstat:JVM Statistics Monitoring Tool
jinfo:Java Configuration Info
jmap:Memory Map
jhat:Java Heap Analysis Tool
jstack:Java Stack Trace
prof:Heap/CPU Profiling Tool
Jconsole:Java Monitoring and Management Console
一般吞吐量优先的应用都有一个较大的年轻代和一个较小的老年代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而老年代尽可能存放长期存活对象
是在垃圾回收算法执行过程中,将jvm内存冻结,停顿的一种状态。
在STW状态下,所有的线程都是停止运行的 - >垃圾回收线程除外。
当STW发生时,除了GC所需要的线程,其他的线程都将停止工作,中断了的线程知道GC线程结束才会继续任务。
STW是不可避免的,垃圾回收算法的执行一定会出现STW,而我们最好的解决办法就是减少停顿的时间。
GC各种算法的优化重点就是为了减少STW,这也是JVM调优的重点。
https://blog.csdn.net/weixin_45505313/article/details/99178527#25__114
https://blog.csdn.net/weixin_45505313/article/details/114089053