目录
1、JVM调优工具
1.1、jps
1.2、jstat
1.3、jstack
1.4、jinfo
1.5、jmap
2、OOM排查过程
2.1、OOM原因
2.2、OOM发生区域
2.2.1、Java堆溢出:heap
2.2.2、Java栈溢出:stack
2.2.3、运行时常量溢出:constant
2.2.4、方法区溢出:directMemory
2.3、OOM排查流程
3、CPU排查过程
3.1、核心步骤排查
3.2、CPU飙升原因分析
- 吞吐量 = CPU运行用户代码时间/(运行用户代码时间+垃圾收集时间);
- 暂停时间 = 执行垃圾回收时,程序的工作线程被暂停的时间;
- 内存占用 = java堆所占内存的大小;
- 收集频率 = 垃圾收集的频次。
1、JVM调优工具
1.1、jps
查看Java进程的工具,可获取所需进程的PID,跟Linux下的ps命令类似。
1.2、jstat
显示虚拟机进程中的类装载、内存、垃圾收集等运行数据。
Jstat [option] VMID 打印间隔时间(ms) 打印次数
1.3、jstack
查看当前Java程序内线程详细堆栈信息的工具,用于生成JVM进程当前时刻的线程的调用堆栈,可以用来定位线程间死锁、锁等待、等待外部资源等。
1.4、jinfo
查看JVM参数、动态修改部分JVM参数。
Jinfo [option] pid
- -flag<name> 打印指定名称的参数
- -flag[+|-]<name> 打开或关闭参数
- -flag<name>=<value> 设置参数
- -flags 打印所有参数
- -sysprops 打印系统配置
1.5、jmap
用于生成堆转储快照dump文件,常用于分析OOM异常情况。
-dump:生成java堆的dump文件
jhat [option] dumpfile:分析jmap生成的dump文件。
2、OOM排查过程
2.1、OOM原因
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 资源使用之后没有及时关闭,导致对象无法被GC回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用的第三方软件中的BUG;
- 启动参数内存值设定的过小;
2.2、OOM发生区域
2.2.1、Java堆溢出:heap
java.lang.OutofMemoryError:Java heap space
原因:内存泄露、JVM内存小、创建太多的对象没有释放。
相关JVM参数:-Xms、-Xmx
2.2.2、Java栈溢出:stack
java.lang.StackOverflowError,常发生于递归。
java.lang.OutofMemoryError: unable to create new native thread,常发生于创建太多线程。
相关JVM参数:-Xss,表示每个线程的堆栈大小。
2.2.3、运行时常量溢出:constant
java.lang.OutofMemoryError: PermGen space。
运行时常量保存在方法区,存放的主要是编译器生成的各种字面量和符号引用,但是运行期间也可能将新的常量放入池中。
-XX:PermSize:设置持久代(perm gen)初始值,默认值为物理内存的1/64
-XX:MaxPermSize:设置持久代最大值,默认为物理内存的1/4
2.2.4、方法区溢出:directMemory
java.lang.OutofMemoryError: PermGen space。
方法区主要存储被虚拟机加载的类信息,如类名、访问修饰符、常量池、字段描述、方法描述等。目前很多框架,如Spring、Hibernate等会在运行过程中动态生成类,所以方法区也有可能发生OOM。
2.3、OOM排查流程
需要先设置JVM参数,设定当发生OOM的时候自动生成dump出堆信息:
- 开启堆快照:-XX:+HeapDumpOnOutOfMemoryError
- OOM时日志记录文件位置:-XX:HeapDumpPath=/usr/local/error.hprof
1、先查看应用pid号:ps -ef|grep 应用名/java;
或者使用jps查看JVM中运行的进程状态信息;
2、查看pid垃圾回收情况:jstat -gc pid 5000(时间间隔)
查看堆内存各部分的使用量,加载类的数量以及GC的情况
3、使用jmap -histo:live pid 显示堆中的详细信息
4、使用jmap -dump:format=b,file=heapdump.phrof pid生成堆存储快照,然后将快照文件使用jvisualvm进行分析;
3、CPU排查过程
3.1、核心步骤排查
- 执行”top”命令:查看所有进程占系统CPU的排序。找出进程号(PID)。
- 执行”top -Hp PID”命令:查看java进程下的所有线程占用CPU的情况。
- 执行printf “%x\n 10”命令 :后续查看线程堆栈信息展示的都是十六进制,所以需要把线程号转成16进制。例如, printf "%x\n 10"->打印:a,那么在jstack中线程号就是0xa.
- 执行 “jstack PID | grep 线程ID”:查找某进程下->线程ID(jstack堆栈信息中的nid)=0xa的线程堆栈信息。如果“"VM Thread" os_prio=0 tid=0x00007f871806e000 nid=0xa runnable”,第一个双引号圈起来的就是线程名,如果是“VM Thread”这就是虚拟机GC回收线程了
- 1、执行“jstat -gcutil 进程号” 统计间隔毫秒 统计次数(缺省代表一致统计)”,查看某进程GC持续变化情况,如果发现返回中FGC很大且一直增大->确认Full GC!
- 2、也可以使用“jmap -heap 进程ID”查看一下进程的堆内从是不是要溢出了,特别是老年代内从使用情况一般是达到阈值(具体看垃圾回收器和启动时配置的阈值)就会进程Full GC。
- 执行“jmap -dump:format=b,file=filename 进程ID”,导出某进程下内存heap输出到文件中。可以通过eclipse的mat工具查看内存中有哪些对象比较多。
3.2、CPU飙升原因分析
- 内存消耗过大,导致Full GC次数过多
- 代码中有大量消耗CPU的操作,导致CPU过高,系统运行缓慢
- 由于锁使用不当,导致死锁
- 随机出现大量线程访问接口缓慢
- 某个线程由于某种原因而进入WAITING状态,此时该功能整体不可用,但是无法复现
以上内容为个人学习理解,如有问题,欢迎在评论区指出。
部分内容截取自网络,如有侵权,联系作者删除。