缘由
最近,一个机器上的tomcat进程莫名消失了,为了暂时解决问题,设置提升了内存设置。但是,之后过了没多久tomcat又消失了。为了排查问题,我仔细分析了机器上的log。
一开始去查看运行目录是否有dump文件,发现并没有,看似并不是OutOfMemoryError的问题, 也没有JVM crash之后会生成的hs_err_pidxxx.log, JVM也没有出错。
再去查看tomcat的日志,发现也没有异常,突然就结束了,看起来也并不是tomcat崩溃了。
不是JVM崩溃,也不是tomcat崩溃,这个让我们很困惑。通过搜索,得知可能是被os杀掉了。
通过demsg
命令,得到如下的输出:
google之后,发现有可能是linux的奇怪特性。
分析
memory overcommit
linux有一个比较奇怪的特性,叫memory overcommit。详细内容可以参考这里。
主要表现就是malloc永远会返回一个合法的指针。举个例子,假设我们的机器有4G内存,有两个JVM,每个JVM都说我要4G,linux仍然会成功的分配给他们。
这个特性对于大多数程序来说没有影响,因为一般程序不会占满自己申请的内存,他们可能只用申请的30%内存,于是相安无事。
JVM and GC
但是对于JVM,尤其是长时间运行的JVM,memory overcommit会有很大影响。
对于大多数GC算法来说,只有在堆分配不出内存的时候才会进行GC活动,释放到达不了的object。
回到上面的例子,假设两个JVM长时间运行,内存都逼近1.5G,对于JVM来说,自己才使用了1.5G内存,可能新生代还很空,没有必要进行GC。但是linux不一样,他知道实际的内存(3G+内核+其他软件,比如vim)可能已经没有多少了,于是启动oom-killer杀死某一个进程(根据运行时间,内存占用等决定),而长时间运行,占用大量内存的Java进程很容易被选择。
总结
综上,如果tomcat真的是每次被内核杀死,要做的不是提高Xmx,Xms,反而是降低。
不过即使不是每次都被内核杀死,我也建议在beta机器上降低内存设置,试着让tomcat长时间的跑,看会不会OutOfMemoryError,并且看看那时JVM产生的dump,更加利于定位内存问题。
另外:
IBM Heap Analyzer其实挺坑爹的(附连接):
他的root object根本不只是gc root,还包含所有可以被gc但是还没有被gc的object。所以他显示的leak suspect根本大多是可回收的对象,容易造成误解。
附
Written with StackEdit.
评论
发表评论