JVM调优问题定位思路和GC日志解读

176 阅读5分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

理论和实践结合

JVM调优关注点

  • GC日志情况
  • 线程栈运行状态和情况
  • 内存使用情况

GC日志解读和分析

-XX:+PrintGCDetail :打印GC日志

-XX:+PrintGCDateStaps:打印gc日志带时间

-Xloggc: GC日志打印到文件中

java运行内存:如果物理内存<1G,默认和物理内存1/2,物理内存>8G,默认是物理内存的1/4.

-Xmx -Xms 设置一样: GC的频繁的开辟空间 堆内存的大小是蓄水池的作用

  • 分析GC日志的工具

  • GCEasy 在线工具 :gceasy.io

  • GCViewer:jar包

产生GC的原因

Full GC 产生的原因

Allocation Failure -- 分配内存失败

Ergonomics -- 在JVM中的垃圾收集器中的Ergonomics就是负责自动的调解gc暂停时间和吞吐量之间的平衡,然后你的虚拟机性能更好的一种做法。 #发现当我们使用Server模式下的ParallelGC收集器组合(Parallel Scavenge+Serial Old的组合)下,担保机制的实现和之前的Client模式下(SerialGC收集器组合)有所变化。在GC前还会进行一次判断,如果要分配的内存>=Eden区大小的一半,那么会直接把要分配的内存放入老年代中。否则才会进入担保机制。 #bool result = padded_average_promoted_in_bytes() > (float) old_free_in_bytes; 晋升到老生代的平均大小大于老生代的剩余大小,则会返回true,认为需要一次full gc

日志解读实践

[GC (Allocation Failure) [PSYoungGen: 65536K->10750K(76288K)] 65536K->22997K(251392K), 0.0047065 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
#分配内存失败,产生一次YoungGC 4毫秒内(GC暂停时间)垃圾回收Young区的内存从65M压缩到10M。压缩了55M。整个Young区最大的容量是762M。整个堆内存的情况从65M压缩到22M,压缩了43M。此次GC过程中有12MYoung区的数据从Young区晋升到Old区。
......
[Full GC (Ergonomics) [PSYoungGen: 10735K->0K(272896K)] [ParOldGen: 200381K->178109K(352256K)] 211117K->178109K(625152K), [Metaspace: 2621K->2621K(1056768K)], 0.0312855 secs] [Times: user=0.19 sys=0.00, real=0.03 secs]

#产生FullGC的原因是:Ergonomics -- 在JVM中的垃圾收集器中的Ergonomics就是负责自动的调解gc暂停时间和吞吐量之间的平衡,然后你的虚拟机性能更好的一种做法。

#发现当我们使用Server模式下的ParallelGC收集器组合(Parallel Scavenge+Serial Old的组合)下,担保机制的实现和之前的Client模式下(SerialGC收集器组合)有所变化。在GC前还会进行一次判断,如果要分配的内存>=Eden区大小的一半,那么会直接把要分配的内存放入老年代中。否则才会进入担保机制。

#bool result = padded_average_promoted_in_bytes() > (float) old_free_in_bytes; 晋升到老生代的平均大小大于老生代的剩余大小,则会返回true,认为需要一次full gc

#Ergonomics产生一次FullGC 31毫秒内(GC暂停时间)垃圾回收Young区的内存从10M压缩到0M(进行FullGC的时候直接把Young区的数据清掉了)。Old区从200M压缩到178M,Old区的容量是352M。整个堆内存的情况从211M压缩到178M,压缩了33M。
......
执行结束!共生成对象次数:14863

JVM堆栈数据分析

JVM线程模型:

JVM内部线程

VM线程:单例VMThread对象

定时任务线程:WatcherThread

GC线程:并行和并发垃圾回收

编译器线程:字节编译机器代码

信号分发线程:进程指示信号

JVM支持多种方式进行线程存储

JVM工具

JDK工具:jstack jcmd jconsole jvisualvm

Shell命令或者控制台,kill -3

JMX技术:主要使用ThreadMxBean

在线分析:fastthread.io/

注:java对象:对象头12字节、对象体 4的倍数补齐

jmap -heap 内存情况

jmap -dump 备份下内存快照

内存泄露:未释放对象引用

OOM java heap space:堆内存空间不足以存放新的对象

产生原因:大对象、超过预期的访问量或者数据量、内存泄露

OOM:PermGen space

解决方法:增加PermGen、MetaSpace空间

OOM:Unable to create new natice thread 错误创建线程数量超过上限

解决思路:

1、调整参数 ulimit -a

2、降低xss等参数

3、调整代码,改变线程创建和使用方式

JVM问题分析调优经验

1、高分配速率 Hign Allocation Rate 表示单位时间内分配的内存量。(上次GC之后留存的新增代的对象 到这一次GC发生之前整个年轻代对象相减 除以 gc间隔时间)

正常系统:分配速率低~回收速率 - >健康

内存泄漏: 分配速率持续大于回收速率 -> OOM

性能劣化: 分配速率很高 ~回收速率 ->亚健康

TODO-实践 看下线上环境分配速率问题

2、过早提升

提升速率 promotion rate 用于衡量单位时间内从年轻代提升到老年代的数据量

1、短时间内频繁执行fullGC

2、每次fullGC后老年代的使用率都很低

3、提升速率接近分配速率

解决方案:

1、增加年轻代的大小,设置jvm启动参数 -XX:NewSize

2、减少每次业务处理使用的内存数量

JVM疑难情况分析

Arthas诊断分析工具

问题定位思路或者方向

  • 查询业务日志
  • 系统资源和监控平台(CPU负载、内存不足、磁盘使用量、硬件故障)
  • 网络问题:流量打满、相应超时、网络抖动
  • 性能指标:实时监控、历史数据、假死、卡顿、响应慢
  • 排查业务系统日志
  • APM:链路
  • 配置文件:启动参数、jvm监控、数据库参数、内存问题、GC问题
  • 资源竞争、坏邻居效应
  • dump线程内存情况,抽样分析、异步化、削峰填谷