最近新做了一个告警监控的APP项目,后台代码只有用户登录管理和告警查询模块,业务量特别少,项目部署服务器上后,发现内置直接飙升至2G,甚至直接OOM,导致服务器系统重启,于是开始寻找原因。
1、首先排查代码,看代码是否存在死循环及循环引用等情况,经过详细排查后,并没有发现任何问题。
2、可能没有设置合适的jvm启动参数,于是设置该参数 。(参考链接)
java -Xms256m -Xmx512m -XX:ParallelGCThreads=2 -Djava.compiler=NONE -jar monitor-0.0.1-SNAPSHOT.jar
通过设定Xmx(程序运行期间最大可占用的内存大小)、Xss(jvm启动的每个线程分配的内存大小)、XX:ParallelGCThreads(GC线程数)以及关闭了JIT功能,达成了降低内存占用的目的。
3、设置项目jvm参数后内存没有继续上升,但是在运行过程中,发现内存会上升到600M左右,自以为能够稳定运行了,结果运行了2个小时后又OOM了
Exception in thread "http-nio-8080-exec-3" Exception in thread "http-nec-4" java.lang.OutOfMemoryError: Java heap space
at java.nio.HeapByteBuffer.<init>(Unknown Source)
at java.nio.ByteBuffer.allocate(Unknown Source)
4、使用jmap进行抓包分析后发现,无论是否内存溢出,都会存在几个对象占用特别大的内存。
这个对象是什么情况,代码里面没有用到呀,5、看线程名称应该是tomcat的nio工作线程,
第一步:打开Histogram看看占用内存最大的是什么对象:
可以看到byte数组占用了接近JVM配置的最大堆的大小也就是400M,显然这是OOM的原因。
第二步: 看一下究竟是哪些byte数组,数组是啥内容,可以看出很明显这和HTTP请求相关。
为了进一步验证猜想,关闭前端调用,只启动后台进程,此时发现内存占用仅在200M左右。进一步使用jmap抓包,没有发现之前内存比较大的那几个对象。当任意调用几个接口后,内存再次飙升,继续抓包分析,发现又出现了几个97.4M的对象,由此已经可以确定,此OOM问题肯定与http请求和tomcat有关。进一步猜想可能是设置了什么不合理的启动参数导致。(一般而言一次请求,不可能会占用这么大的内存。)
第三步: 通过查看GC根查看谁持有了数组的引用:
这符合之前的猜测,是tomcat的线程在处理过程中分配了97.7M的buffer在堆上。
第四步: 检查代码里是否有tomcat或服务器相关配置,看到有这么一个配置:
server.maxHttpHeaderSize=102400000
server.tomcat.max-http-post-size=102400000
至此,基本已经确定了可能就是这个不合理的最大配置参数导致的问题。注销该代码后,进一步部署验证,发现问题已解决。
网友评论