jvm重要参数可视化和线上问题排查
目标
- 熟悉常用的 jvm参数 含义,默认值
- 了解配置这些默认值的一般原则
- 线上排查内存溢出的步骤和常见原因分析
jvm参数
分类(了解)
- 根据jvm参数开头可以区分参数类型,共三类:
-
、-X
、-XX
标准参数(-)
:所有的JVM实现都必须实现这些参数的功能,而且向后兼容非标准参数(-X)
:默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容- 例子:
Xms20m,-Xmx20m,-Xmn20m
- 例子:
非Stable参数(-XX)
:此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用;- 例子:
-XX:+PrintGCDetails,-XX:-UseParallelGC,-XX:+PrintGCTimeStamps
- 例子:
运行时数据区相关的(jdk1.8)
- 程序计数器(无参数)
- 虚拟机栈(本地方法栈)
-Xss
: stack size 设置每个线程的栈大小,等同于-XX:ThreadStackSize
- 方法区(元空间)
-XX:MetaspaceSize
: 设置 Metaspace 的初始(和最小大小)-XX:MaxMetaspaceSize
: 设置 Metaspace 的最大大小- 1.8 之前使用
-XX:PermSize
-XX:MaxPermSize
- 堆
- 求和
- 堆内存 = 新生代(Young Generation) + 老年代() ; 新生代 = Eden + S0 + S1
-Xms
: memory size 设置jvm初始化堆大小-Xmx
: memory max 设置jvm初始化堆最大值,等同于-XX:MaxHeapSize
-XX:NewRatio
: 设置 新生代 和 老年代 的比例- 新生代
-XX:SurvivorRatio
: 设置 新生代内部的 比例- 一共有两种指定 新生代内存(Young Generation)大小的方法
- 通过
-XX:NewSize
和-XX:MaxNewSize
指定 初始值和最大值 - 通过
-Xmn
memory new 设置新生代大小,NewSize 与 MaxNewSize 设为一致
- 通过
- 老年代
-XX:MaxTenuringThreshold
: 新生代中对象存活次数,默认15。(若对象在eden区,经历一次MinorGC后还活着,则被移动到Survior区,年龄加1。以后,对象每次经历MinorGC,年龄都加1。达到阀值,则移入老年代)
- 求和
处理 OOM 相关的
- 线上环境比配,方便分析内存溢出
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./java_pid<pid>.hprof
- 了解
-XX:OnOutOfMemoryError="< cmd args >;< cmd args >"
-XX:+UseGCOverheadLimit
垃圾回收器相关的
- 埋个坑
GC 日志记录相关的
- 埋个坑
意义,默认值,调优原则(重要, 待拆分)
- 虚拟机栈
-
Xss1024k
等同于-XX:ThreadStackSize=1024k
- 意义:设置线程栈占用内存大小。
注意:一般在相同物理内存下,如果减少-xss值会产生更大的线程数,但不同的操作系统对进程内线程数是有限制的,是不能无限生成。
-
- 堆内存
-
-Xms2G -Xmx4G
- 意义:设置堆内存的初始值和最大值。
建议:通常这两个配置参数相等,可以使得堆相对稳定,避免不停震荡,动态扩容
-
- 新生代
-
方法一:
Xmn256m
- 为 新生代分配 256m 的内存(NewSize 与 MaxNewSize 设为一致)
-
方法二:
-XX:NewSize=256m -XX:MaxNewSize=1024m
- 设置新生代的初始值和最大值。
注意:不要将 -mn 和 -mx 设置相等,会导致 没有老年代,进而 oom。 -mn 过小会增加Minor GC频率,过大会减小老年代的大小。一般设为整个堆空间的1/4或1/3.
-
排查 OOM 流程 和 常见原因
- 对于线上环境,设置参数,拿到 oom 时堆内存快照
- 线上环境一般不能使用 jdk自带的故障分析工具,需要提前保存 堆内存快照
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=/app/logs/app.dump
- 使用快照分析工具分析 堆内存快照
- MAT(Memory Analyzer Tool)
- jvisualvm
- 常见的问题和原因
- java.lang.OutOfMemoryError: Java heap space
- 首先肯定这是一个堆内存空间引起的问题,可能的原因有:
- 内存加载数据量过大
- 例如不受行数限制的数据库查询语句,或者不限制字节数的文件读取等,事故系统显然没有这些情况;
- 内存泄漏(资源未关闭/无法回收)
- 当系统存在大量未关闭的 IO 资源,或者错误使用ThreadLocal等场景时也会发生OOM,经排查,也不存在这种情况;
- 系统内存不足
- 系统内存不足以支撑当前业务场景所需要的内存,过小的机器内存或者不合理的JVM内存参数。
- 内存加载数据量过大
- 首先肯定这是一个堆内存空间引起的问题,可能的原因有:
- java.lang.OutOfMemoryError: Java heap space