我正在对一个 tomcat 服务器进行负载测试。服务器有 10G 物理内存和 2G 交换空间。堆大小(xms 和 xmlx)之前设置为 3G,服务器运行良好。由于我仍然看到剩余的可用内存很多且性能不佳,我将堆大小增加到 7G 并再次运行负载测试。这次我观察到物理内存很快被吃光了,系统开始消耗交换空间。后来tomcat用完swap空间就崩溃了。我在启动 tomcat 时包含了 -XX:+HeapDumpOnOutOfMemoryError
,但没有得到任何堆转储。当我检查 /var/log/messages
时,我看到 kernel: Out of memory: Kill process 2259 (java) score 634 or vesting 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
开始加载 10 分钟后(就在 tomcat 被杀死之前):
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?为什么它直接使用交换?
- 为什么
top
RES
显示java用了5.3G内存,内存消耗多了?
我已经调查和搜索了一段时间,仍然找不到这个问题的根本原因。非常感谢!
最佳答案
Why would this issue happen? When JVM runs out of memory why is there no OutOfMemoryException thrown?
内存不足的不是 JVM。 主机操作系统已耗尽内存相关资源,正在采取剧烈行动。操作系统无法知道进程(在本例中为 JVM)在响应更多内存请求而被告知“否”时能够以有序的方式关闭。它必须硬杀某些东西,否则整个操作系统都会挂起的严重风险。
无论如何,您没有看到 OOME 的原因是这不是 OOME 情况。实际上,JVM 已经被操作系统给予了太多内存,并且没有办法收回。这就是操作系统必须通过硬杀进程来处理的问题。
And why does it go straight to using swap?
它使用交换,因为整个系统的总虚拟内存需求不适合物理内存。这是 UNIX/Linux 操作系统的正常行为。
Why top RES shows that java is using 5.3G memory, there's much more memory consumed
RES 数字可能有点误导。他们指的是进程当前正在使用的物理内存量......不包括与其他进程共享或可共享的东西。 VIRT 编号与您的问题更相关。它说您的 JVM 正在使用 10.4g 的虚拟内存......这比您系统上的可用物理内存更多。
正如另一个答案所说,令人担忧的是,您没有获得 OOME。即使你确实得到了一个,用它做任何事情都是不明智的。 OOME 可能会对您的应用程序/容器造成附带损害,这些损害难以检测和恢复。这就是为什么 OOME 是 Error
而不是 Exception
。
建议:
不要尝试使用比物理内存多得多的虚拟内存,尤其是在 Java 中。当 JVM 运行完整的垃圾回收时,它会以 随机 的顺序多次 接触其 VM 页面的大部分。如果您过度分配内存,很可能会导致抖动,从而影响整个系统的性能。
请增加系统的交换空间。 (但这可能无济于事......)
不要尝试从 OOME 中恢复。
关于java - Tomcat 进程在交换空间用完后被 Linux 内核杀死;没有任何 JVM OutOfMemory 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17203111/