参数配置
先确保jvm有以下配置,可以在遇到异常时方便快速排查。
#Java fatal error(致命错误即jvm crash)日志目录
-XX:ErrorFile=/logs/hs_err_pid%p_%t.log
# gc日志文件名
-Xloggc:gc.log
# oom dump
-XX:+HeapDumpOnOutOfMemoryError 用于内存溢出产生hprof文件
-XX:HeapDumpPath=/heapdump
# gc日志
-Xloggc:gc.log 日志文件名
-XX:+PrintGCDetails 打印GC详细信息
-XX:+PrintGCDateStamps 打印GC停顿时间
JVM崩溃进程消失
1.查看是否生产hs_error文件。(jvm crash)
2.查看是否生成dump文件。(oom)
3.查看demesg消息。(系统kill)
当机器内存被占满,系统自动选择一个占用内存最大的进行kill掉。
# dmesg:用来显示内核相关的信息。
dmesg|grep -i kill | less 或 dmesg|grep kill
OOM
Exception in thread “main” java.lang.OutOfMemoryError: unable to create new native thread
没有足够的内存空间给线程分配java栈.
- 可指定-Xss来减少单个thread stack的大小。
- 通过jstack排查线程数量,确认是否存在大量创建线程的情况。
#查看进程线程数 top -Hp $pid ps -T -p $pid # 通过jstack 分析线程 jstack $pid
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
堆的内存占用已经达到-Xmx设置的最大值
- 设置更大-Xmx值。
- 通过MAT或其他工具分析dump文件确认是否存在异常。
Caused by: java.lang.OutOfMemoryError: Metaspace
元数据区的内存占用已经达到-XX:MaxMetaspaceSize设置的最大值,
- 通过-XX:MaxMetaspaceSize来进行调整。
- 通过jmap dump内存日志分析元数据是否存在重复创建类加载器加载类的情况。
#打印类加载器信息 jmap -F -clstats PID # dump jmap -dump:format=b,file=./a.hprof PID
java.lang.OutOfMemoryError: GC overhead limit exceeded
GC开销限制,JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存,导致频繁的进行内存回收(连续5次以上垃圾回收)
- 通过gc日志和dump内存分析是否存在异常。
- 优化heap区域分配比例
FullGC频繁
1. 通过gc日志判断引起fullgc的区域。
MetaSpace 引起的fullgc:可通过jmap -histo $pid 和 jmap -clstats $pid 分析元数据空间是否重复加载相同类导致空间不足。
Metadata GC Threshold:metaspace空间不能满足分配时触发,这个阶段不会清理软引用;
Last ditch collection:经过Metadata GC Threshold触发的full gc后还是不能满足条件,这个时候会触发再一次的gc cause为Last ditch collection的full gc,这次full gc会清理掉软引用。
老年代 引起fullgc
-
在新生代对象转入及创建为大对象时出现老年代空间不足现象,当执行Full GC后空间仍然不足抛出java.lang.OutOfMemoryError: Java heap space。以上两种状况引起的Full GC,调优时应尽量做到让对象在Minor GC阶段被回收、让对象在新生代多存活一段时间及不要创建过大的对象及数组。
-
CMS GC时出现promotion failed和concurrent mode failure:promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入老年代,而此时老年代也放不下造成的。concurrent mode failure是在执行CMS GC的过程中同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。对措施为:增大survivor space、老年代空间或调低触发并发GC的比率。
-
堆中分配很大的对象。大量连续内存空间的java对象,例如很长的数组,会直接进入老年代,而老年代虽然有很大的剩余空间,但是无法找到足够大的连续空间来分配给当前对象,此种情况就会触发JVM进行Full GC。CMS垃圾收集器提供了一个可配置的参数,即-XX:+UseCMSCompactAtFullCollection开关参数,用于在“享受”完Full GC服务之后额外免费赠送一个碎片整理的过程,内存整理的过程无法并发的,空间碎片问题没有了,但提顿时间不得不变长了,JVM设计者们还提供了另外一个参数 -XX:CMSFullGCsBeforeCompaction,这个参数用于设置在执行多少次不压缩的Full GC后,跟着来一次带压缩的。
CUP高
top -c找到CPU高的进程PID
top -Hp PID shift+t查看cpu使用率高的线程
printf '%x\n' 线程pid将线程pid转换为16进制的nid
jstack PID | grep -A 20 nid # 获取线程堆栈信息
jstack PID | grep nid -C5 –color 获取线程堆栈信息
- 关注 WAITING、TIMED_WAITING、BLOCKED状态线程
- jstat -gcutil pid 3s 10分析是否存在频繁GC
- pidstat -w pid分析上下文切换
内存高
内存组成
问题排查
free -h 命令查看机器内存情况。
通过jmap -heap $pid or jstat -gccapacity $pid 查看进程占用内存情况,确定占用内存高的区域。
堆外内存:pmap -x $pid | sort -rn -k3 | head -30 查看对应pid倒序前30大的内存段。
线程池满
- 通过jstack $pid 导出堆栈信息。
- 排查堆栈信息中是否存在大量线程等待。
- 业务层面排查线程处理是否能快速完成。