最近线上应用发生了OOM , 该应用是部署在tomact8上, 发生OOM后,运维打印了线程dump和内存dump。
当时,第一反义就觉得都OOM了,打印的线程dump 和内存dump 应该不可靠,但是也没办法,看下再说。
首先,我用MAT 分析内存dump, 大小内存才用973M, 顿时很奇怪,这怎么会内存溢,由此证明,OOM
打印的内存dump 无效。
接着去分析Thread dump , 发现大量tomcat 的线程被block, 没有看到那个线程挂了业务。Tomcat8 默认是NIO, tomcat6默认是BIO。
线程信息如下:
线程栈如下:
"http-nio-9091-exec-1163" #143870 daemon prio=5 os_prio=0 tid=0x00007fc67401b000 nid=0x3c4c waiting for monitor entry [0x00007fc6e68e9000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.apache.coyote.AbstractProtocol$RecycledProcessors.clear(AbstractProtocol.java:877)
- waiting to lock <0x00000000feb52cf0> (a org.apache.coyote.AbstractProtocol$RecycledProcessors)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.recycle(AbstractProtocol.java:588)
at org.apache.tomcat.util.net.NioEndpoint.releaseCaches(NioEndpoint.java:310)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1610)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
- locked <0x00000000cbba6658> (a org.apache.tomcat.util.net.NioChannel)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
看到大量的tomcat线程都阻塞在这里,我猜测,这个应该是OOM后,tomcat自身的行为,结合线程堆栈,对应响应的源码分析
发现发送OOM后,tomcat会释放资源,源码片段如下:
定位到这里,可以肯定OOM后,取得dump 都是失效的,没有用。
总结: thread dump 里面有线程执行的路径,对应响应的源码,就可以解释线程的状态,因此看到线程栈,不要怕,对应源码,Nothing is fear。
这个问题,也反应出,我们在jvm 启动的时候,应该配置-XX:+HeapDumpOnOutOfMemoryError.
博客讲述了作者在分析线上应用的Tomcat8 OOM问题时,发现大量http-nio线程被阻塞在等待锁。通过MAT分析内存dump发现内存使用正常,然后通过线程dump分析,发现在AbstractProtocol$RecycledProcessors.clear方法中存在线程竞争。作者认为这是由于OOM后Tomcat释放资源导致的,分析源码进一步证实了这一点,并建议在JVM启动时配置-XX:+HeapDumpOnOutOfMemoryError以获取有效的内存dump。

1018

被折叠的 条评论
为什么被折叠?



