目录
一个生产的OOM
1.生产报了一个异常,java.lang.OutOfMemoryError: Java heap space,如下
每次操作能复现。初看像是堆内存溢出了。所以决定dump出来看看
跟踪操作
查看jvm进程
ps -ef | grep java
拿到pid号4447
生成dump文件
切换到root用户:sudo su-
jmap -dump:live,format=b,file=test_heap.bin 4447
会生成dump文件:test_heap.bin.然后通过跳板机jumpserver从服务器上down下来
分析dump文件
分析dump文件有几种方式
- jhat命令。以我的为例,把dump文件放到window的盘下面,打开cmd,运行命令接着访问 http://localhost:7001/,就可以分析对应的实例关系。
- VisualVM。大家试过就会发现,上面一种方式,查看起来不是很方便,可以利用Jdk自带的图形化工具VisualVM。
发现char[]占比已经85%了,然后就可以分析它的引用关系,可能还要根据代码检查,需要一定的时间与经验。
后面发现是一个循环里面的不断的生成StringBuffer变量sb,导致最后sb.append的字符越来越长,最终导致oom。后来修改了业务逻辑,没再出过对应的异常了
所以,在此,记录并总结下,这类问题一般的应对方法(个人经验哈,不保证绝对正确,不代表方法最佳)。
Jdk自带的命令
Jps (JVM Process Status Tools)
用于查看正在运行的虚拟机进程以及对应的ID,对应本机来说和PID相同(类似ps -ef | grep jav)
Option | Function |
-q | 只输出LVMID |
-m | 输出JVM启动时传给主类的方法 |
-l | 输出主类的全名,如果是Jar则输出jar的路径 |
-v | 输出JVM的启动参数 |
Jmap (JVM Memory Map for Java)
上面例子,用到了jmap生成堆转储快照
jmap -dump:live,format=b,file=test_heap.bin 4447
查看一下帮助
除了生成堆转储外,还有一个很重要的用途是查看堆信息
jmap -heap 22220
jmap的作用不仅仅是为了获取dump文件,还可以用于查询finalize执行队列、Java堆和永久带的详细信息,如空间使用率、垃圾回收器等。
Option | Function |
-dump | 生成对应的dump信息,用法为-dump:[live,]format=b,file={fileName} |
-finalizerinfo | 显示在F-Queue中等待的Finalizer方法的对象(只在linux下生效) |
-heap | 显示堆的详细信息、垃圾回收器信息、参数配置、分代详情等 |
-histo | 显示堆栈中的对象的统计信息,包含类、实例数量和合计容量 |
-permstat -F | 以ClassLoder为统计口径显示永久带的内存状态 当虚拟机对-dump无响应时可使用这个选项强制生成dump快照 |
Jinfo (JVM configuration Info for Java)
Jinfo的作用是实时查看虚拟机的各项参数信息jps –v可以查看虚拟机在启动时被显式指定的参数信息,但是如果你想知道默认的一些参数信息呢?除了去查询对应的资料以外,jinfo就显得很重要了
Jstat(JVM Statistics Monitoring Tools)
jstat主要用于监控虚拟机的各种运行状态信息,如类的装载、内存、垃圾回收、JIT编译器等
可以监控gc的状况:第3秒钟输出一次gc的状态,连续查10次
Option | Function |
-gc | 监视Java堆,包含eden、2个survivor区、old区和永久带区域的容量、已用空间、GC时间合计等信息 |
-gccapcity | 监视内容与-gc相同,但输出主要关注Java区域用到的最大和最小空间 |
-gcutil | 监视内容与-gc相同,但输出主要关注已使用空间占总空间的百分比 |
-gccause | 与-gcutil输出信息相同,额外输出导致上次GC产生的原因 |
-gcnew | 监控新生代的GC情况 |
-gcnewcapacity | 与-gcnew监控信息相同,输出主要关注使用到的最大和最小空间 |
-gcold | 监控老生代的GC情况 |
-gcoldcapacity | 与-gcold监控信息相同,输出主要关注使用到的最大和最小空间 |
-gcpermcapacity | 输出永久带用到的最大和最小空间 |
-compiler | 输出JIT编译器编译过的方法、耗时信息 |
-printcompilation | 输出已经被JIT编译的方法 |
-class | 监视类的装载、卸载数量以及类的装载总空间和耗费时间等 |
Jhat (JVM Heap Analysis Tool)
jhat是用来分析dump文件的一个微型的HTTP/HTML服务器,它能将生成的dump文件生成在线的HTML文件,让我们可以通过浏览器进行查阅
然而实际中我们很少使用这个工具,因为一般服务器上设置的堆、栈内存都比较大,生成的dump也比较大,直接用jhat容易造成内存溢出,而是我们大部分会将对应的文件拷贝下来,通过其他可视化的工具进行分析。
Jstack(JVM Stack Trace for java)
jstack用于JVM当前时刻的线程快照,又称threaddump文件,它是JVM当前每一条线程正在执行的堆栈信息的集合。看下用法,如下图
再看下当前进程的情况
生成线程快照的主要目的是为了定位线程出现长时间停顿的原因,如线程死锁、死循环、请求外部时长过长导致线程停顿的原因。通过jstack我们就可以知道哪些进程在后台做些什么?在等待什么资源等!
Option | Function |
-F | 当正常输出的请求不响应时强制输出线程堆栈 |
-l | 除堆栈信息外,显示关于锁的附加信息 |
-m | 显示native方法的堆栈信息 |
获取dump文件的几种方式
- jmap命令
jmap -dump:live,format=b,file=test_heap.bin 4447
- 配置参数 在JVM的配置参数中可以添加
-XX:+HeapDumpOnOutOfMemoryError
参数,当应用抛出 OutOfMemoryError 时自动生成dump文件; - Linux环境下还可以使用kill -3 pid恐吓JVM生成dump文件
参与资料:Jvm监控工具