JVM实战(1)-死锁、CPU爆满、堆溢出/泄漏问题

定位 - 死锁

首先如果是本地开发环境可以通过JVisualVM查看是否有长时间休眠的线程。

注意:正式部署版本不会用JVisualVM,否则会留下漏洞

一、jdk自带的jstack排查死锁

需要以下几步:

1. 命令:jps 查看服务器上所有java服务进程。

2. 命令:jstack PID 打印当前服务运行的所有线程快照,

              也可以通过jstack PID > a.txx 例如:将线程快照输出到文件中便于查看,文档的最下发会显示该进程中存在多少个死锁

3. 快照文件内直接搜deadlock如果有结果表示存在死锁

    有提示那行代码出现了死锁,以及为什么死锁的提示。

    快照中对死锁提示:

      - 可以看到线程A,当前拥有的lock锁名为AA,需要获取名为BB的锁;

      - 线程B,拥有的lock锁名为BB,需要获取名为AA的锁;

      - 所以线程A和线程B就会产生死锁。

最后根据提示死锁出现在代码的位置,自行去查看修改代码。

二、jdk自带的jconsole排查死锁

\jdk\jdk8\bin\jconsole.exe

说明:jconsole可以监视本地java进程和远程java进程,

           监视远程java进程需要配置用户名、口令。

 排查死锁 -》点击“检测死锁”按钮

定位 - CPU爆满

1. 定位到哪一个程序CPU占用率高(定位进程PID)

   使用top命名查看服务器cpu使用情况:

2. 定位是那个JAVA程序

  1. jps -l | grep 进程pid

  2. jps -v | grep 进程pid

  3. jps 进程pid

这行命令的作用是通过jps -l打印进程pid对应的java程序是哪一个,至于grep只是为了过滤。 

3. 定位到哪一个线程CPU占用率高  (定位线程TID)

ps -mp 进程pid -o THREAD,tid,time

  通过此命令来获取CPU占用高的线程TID

    

     通过%CPU和TIME,判断占用高的线程TID;

     需要将上图中的TID,转换成16进制(如:21111转为16进制=18a8),然后在下面的第四步(jstack 进程id > ps.txt)导出的文件中搜索,就可以定位到具体有问题的线程,类。

  例如:TID=21111 那么将21111转为16进制就是0x18a8

4. 打印进程的线程快照

jstack 进程pid > t.txt 

  命令说明:输出该进程线程快照到t.txt文件中。

      

内存溢出、泄漏

oom异常分为两种情况:

1.内存溢出:存在未被回收的大对象。 

2.内存泄漏:新生代和老年代中的对象未被回收导致堆爆满。

1. 输出gc日志到指定文件 -Xloggc:

(例如:  -Xloggc:D:\logs\gc.log)

生产环境会对输出的gc日志进行分块输出(防止单个文件过大)https://mp.csdn.net/console/editor/html/106739504

2. 配置jvm参数:内存溢出后打印日志输出到.dump文件中

   -XX:+HeapDumpOnOutOfMemoryError  -XX:HeapDumpPath=/tmp/heapdump.dump 来指定dump路径

 3. 完整的启动jar命令:

    jar - jar -XX指定gc日志输出目录 -xx内存溢出时候打印堆内存快照 -xx指定堆溢出快照日志输出目录

java -jar -Xloggc:/tmp/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.dump Demo-0.0.1-SNAPSHOT.jar

生成的.dump快照文件非常大 = 堆内存大小。

注意 jmap命令也可以打印堆快照,但是会暂停服务的运行(生产环境不允许用jmap取堆快照)。

4. 打印堆内存状态: 命令:jstat -gcutil PID

SO、S1、Eden、O为老年代、M为元空间(方法区)、  CCS、YGC=新生代gc次数、YGCT=新生代gc耗时、FGC=老年代gc次数、FGCT=老年代gc耗时、GCT=所有gc一共耗时。

定位 - 内存溢出

1. 程序里有大对象。

2. 大对象被谁引用。

通过jVisualVM打开.dump堆快照:

2. 导入之后

visualvm概要页会提示:具体线程http-nio-8080-exec-1出现OutOfmEemoryError异常。

点击概要页最下方的"显示线程"按钮,显示线程快照,从中找到(搜索)http-nio-8080-exec-1线程,可以定位到内存溢出的具体类、代码行。

定位 - 内存泄漏

定位方法和内存溢出相同。

如果查找大对象 - 通过visualvm中的"类"查找大对象。


内存溢出实战

1. 设置jvm参数,OutOfMemoryError时打印当前内存快照到指定文件中。

2. 不断往堆内存中添加数据,报OutOfMemoryError后会将当前内存快照输出到指定目录的heapdump.dump文件中

3. 打开jvisualvm.exe,点击文件->装入,选中heapdump.dump文件打开。

       

3.1. 通过“类”来查看到类的实例数量,36w多个实例...

猜你喜欢

转载自blog.csdn.net/adparking/article/details/119604634