我正在对一个Tomcat服务器执行负载测试。该服务器具有10G物理内存和2G交换空间。在此之前,堆大小(xms和xmx)已设置为3G,并且服务器运行正常。由于我仍然看到很多剩余内存且性能不佳,因此我将堆大小增加到了7G并再次运行了负载测试。这次我观察到物理内存被迅速耗尽,系统开始消耗交换空间。后来,Tomcat在耗尽交换空间后崩溃了。我在启动Tomcat时包含了-XX:+HeapDumpOnOutOfMemoryError
,但我没有得到任何堆转储。当我检查/var/log/messages
时,我看到kernel: Out of memory: Kill process 2259 (java) score 634 or sacrifice child
。
为了提供更多信息,以下是设置堆大小为3G和7G时从Linux top
命令中看到的内容:
xms&xmx = 3G(工作正常):
启动tomcat之前:
Mem: 10129972k total, 1135388k used, 8994584k free, 19832k buffers Swap: 2097144k total, 0k used, 2097144k free, 56008k cached
启动Tomcat之后:
Mem: 10129972k total, 3468208k used, 6661764k free, 21528k buffers Swap: 2097144k total, 0k used, 2097144k free, 143428k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2257 tomcat 20 0 5991m 1.9g 19m S 352.9 19.2 3:09.64 java
开始负载10分钟后:
Mem: 10129972k total, 6354756k used, 3775216k free, 21960k buffers Swap: 2097144k total, 0k used, 2097144k free, 144016k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2257 tomcat 20 0 6549m 3.3g 10m S 332.1 34.6 16:46.87 java
xms&xmx = 7G(导致Tomcat崩溃):
在启动Tomcat之前:
Mem: 10129972k total, 1270348k used, 8859624k free, 98504k buffers
Swap: 2097144k total, 0k used, 2097144k free, 74656k cached
启动 Tomcat 后:
Mem: 10129972k total, 6415932k used, 3714040k free, 98816k buffers
Swap: 2097144k total, 0k used, 2097144k free, 144008k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2310 tomcat 20 0 9.9g 3.5g 10m S 0.3 36.1 3:01.66 java
在tomcat被杀掉之前的10分钟开启负载:
Mem: 10129972k total, 9960256k used, 169716k free, 164k buffers
Swap: 2097144k total, 2095056k used, 2088k free, 3284k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2310 tomcat 20 0 10.4g 5.3g 776 S 9.8 54.6 14:42.56 java
Java和JVM版本:
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode)
Tomcat版本:
6.0.36
Linux服务器:
Red Hat Enterprise Linux Server release 6.4 (Santiago)
所以我的问题是:
- 为什么会出现这个问题?当JVM内存耗尽时为什么没有抛出OutOfMemoryError?而且为什么直接使用交换空间(swap)?
- 为什么
top
命令中显示java使用了5.3G内存,实际消耗的内存要多得多?
我已经调查和搜索了一段时间,仍然找不到这个问题的根本原因。非常感谢!
jmap
来获取堆转储。如果大部分内存都来自一个地方,Eclipse MAT可能是分析转储的最简单方法。 - AngerClownnetstat
检查打开的连接 - 导致本机内存使用泄漏的最可能原因是Web容器线程。 - AngerClown