【JVM深入理解系列6】OOM调优

JVM OOM

  • 堆区
    Heap
  • 方法区
    Per
  • 栈区
    StackOverFlow

元空间

调优参数

1
2
-XX:MetaspaceSize=10m
-XX:MaxMetaspaceSize=10m

1、最大、最小设置成一样大。
2、程序运行起来后,通过visualVM、arthas查看占用了多少内存,向上调优,预留20%以上的空间。

虚拟机堆

1
2
3
4
5
6
7
[GC (Allocation Failure) [PSYoungGen: 1344K->320K(2048K)] 7894K->7118K(9216K), 0.0071516 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

[GC类型 (GC原因) [新生代垃圾收集器: gc前新生代的内存使用情况->gc后新生代的内存使用情况(新生代总内存)] gc前堆内存的使用情况->gc后堆内存的使用情况(堆总内存), gc耗时] [Times: gc阶段用户空间耗时 gc阶段内核空间耗时, gc阶段实际耗时]

[Full GC (Ergonomics) [PSYoungGen: 320K->0K(2048K)] [ParOldGen: 6798K->5930K(7168K)] 7118K->5930K(9216K), [Metaspace: 9296K->9233K(1058816K)], 0.6733958 secs] [Times: user=1.76 sys=0.00, real=0.68 secs]

[GC类型 (GC原因) [新生代垃圾收集器: gc前新生代的内存使用情况->gc后新生代的内存使用情况(新生代总内存)] [老年代垃圾收集器: gc前老年代的内存使用情况->gc后老年代的内存使用情况(新生代总内存)] gc前堆内存的使用情况->gc后堆内存的使用情况(堆总内存), [Metaspace: gc前元空间的内存使用情况->gc后元空间的内存使用情况(元空间总内存)], gc耗时] [Times: gc阶段用户空间耗时 gc阶段内核空间耗时, gc阶段实际耗时]
  • 调优参数

-Xms10m -Xmx10m

1、预留30%以上的空间
2、周期性看日志,重点关注full gc频率

虚拟机栈

  • 调优参数

-Xmss200k

栈大小相同,栈深度不同,为什么?
因为栈上会分配数据。导致栈帧变大。深度会变浅。

调优工具

  1. jps

-q:只显示Java进程的ID

-m:输出Java进程的ID + main函数所在类的名词 + 传递给main函数的参数

-l:输出Java进程的ID + main函数所在类的全限定名(包名 + 类名)

-v:输出Java进程的ID + main函数所在类的名称 + 传递给JVM的参数
应用:可通过此方式快速查看JVM参数是否设置成功

-V、hostid基本用不到,这里就不做介绍了,感兴趣的同学可以自行百度学习。

  • 如何识别Java进程

jps输出的信息全是Java进程的信息,是如何做到的?

Java进程在创建的时候,会生成相应的文件,进程相关的信息会写入该文件中。Windows下默认理解是

  1. jstate

Hotspot自带的工具,通过该工具可实时了解某个进程的class、compile、gc、memory的相关信息。具体可通过该工具查看哪些信息可通过jstat -options查看.

为什么说是实时呢,因为底层实现是mmap,及内存映射文件

  • jstat输出的这些值从哪来的
    PerfData文件
    Windows下默认理解是C:\Users\username\AppData\Local\Temp\hsperfdata_username
    Linux下默认路径是/tmp/hsperfdata_username

  • PerfData文件

1、文件创建
取决于两个参数
-XX:-/+UsePerfData
默认是开启的
关闭方式:-XX:-UsePerfData。如果关闭了,就不会创建PerfData文件
-XX:-/+PerfDisableSharedMem(禁用共享内存)
默认是关闭的,即支持内存共享。如果禁用了,依赖于PerfData文件的工具就无法正常工作了
2、文件删除
默认情况下随Java进程的结束而销毁
3、文件更新
-XX:PerfDataSamplingInterval = 50ms
即内存与PerfData文件的数据延迟为50ms

纯Java编写
\openjdk\jdk\src\share\classes\sun\tools\jstat\Jstat.java

3、jinfo
4、jstack
5、jmap
6、jconsole
7、visualVM
8、arthas

Java agent

1、命令行
2、attach

实战

1、统计线程数

1
jstack -l 6972 | grep 'java.lang.Thread.State' | wc -l

2、检测死锁

可使用jstack、jconsle、visualVM

3、CPU占用过高

  1. 定位到占用CPU最高的进程
1
top -H -p 6290

线程ID由十进制转成十六进制,用Python

jstack 6290(进程ID)|grep 18a1(线程ID,十六进制) -A 30

问题:
模拟OOM并思考如何调优
死锁、CPU占用过高问题排查
Java Agent的两种实现方式自己写DEMO