likes
comments
collection
share

JVM系统优化实践(21):GC生产环境案例(四)

作者站长头像
站长
· 阅读数 13

您好,这里是「码农镖局」掘金小站,欢迎您来,欢迎您再来~


前面说了一般应用的OOM情况,但是OOM不知发生在应用层,有时候专门负责运行Java的Tomcat也会偶尔罢工一下,抛出OOM异常。因为Tomcat本身也是一个JVM进程。

  JVM系统优化实践(21):GC生产环境案例(四)

 

为了复现Tomcat的OOM,可以给JVM加上下面的参数:

-XX:+HeapDumpOnOutOfMemoryError

当内存发生OOM时导出一份快照到指定的位置,默认导出的快照文件存放在应用的根目录。

通过追溯问题可以定位问题:

1、Tomcat线程会创建大量的byte[]数组;

2、每秒请求才100,但每个请求都需要4秒的时间;

3、Tomcat配置文件出现了max-http-header-size:10000000;

4、这个配置导致Tomcat工作线程在处理请求时会创建2个数组;

5、400 × 2 × 10000000 = 8G,内存OOM;

6、之所以处理时间长达4秒是因为RPC超时,超时时间刚好设置4秒;

7、问题根本原因是下游故障导致请求失败,整个系统卡住直到超时结束。

JVM系统优化实践(21):GC生产环境案例(四)

JVM系统优化实践(21):GC生产环境案例(四)

所以相应的优化方案也很简单:

1、先解决上下游的系统故障;

2、将超时时间调整为1秒;

3、将Tomcat参数max-http-header-size适当调小。

 

除了Tomcat,在一些非常轻量级的应用中,Jetty也会被部署到生产环境中。这是使用Jetty堆外内存发生的一次OOM。Direct buffer memory,就是堆外内存,是JVM堆内存之外的一块内存空间,不属于JVM管理范畴。

JVM系统优化实践(21):GC生产环境案例(四)

 

Jetty使用DirectByteBuffer类申请堆外内存空间,DirectByteBuffer对象存储在JVM堆内存中。因此当DirectByteBuffer对象没人引用了成了垃圾对象之后,会在Young GC或者Full GC时被回收掉。

  JVM系统优化实践(21):GC生产环境案例(四)

 

这种情况经常发生在:

1、当系统承载超高并发,瞬时请求很大时;

2、当创建了很多DirectByteBuffer对象且还没被回收时继续创建更多DirectByteBuffer对象。

那么在本案例中导致OOM的原因是:

1、通过jstat分析JVM运行情况发现,系统并发量并不高,但每个请求处理较为耗时;

2、系统上线时内存分配不合理,年轻代与老年代的比例为1:4,导致S0/S1极小;

3、Java NIO会主动调用System.gc()完成JVM的垃圾回收;

4、JVM参数中增加-XX:+DisableExplicitGC,这个参数使得显式调用垃圾回收不生效;

5、由此导致堆外OOM的故障。

 

解决方案是:

1、合理分配内存,给年轻代更多内存;

2、放开-XX:+DisableExplicitGC,让System.gc()生效。


感谢您的大驾光临!欢迎骚扰,不胜荣幸~