Tomcat进程在交换空间不足后被Linux内核杀死; 不要得到任何JVM OutOfMemory错误

我正在对tomcat服务器进行负载testing。 服务器有10G物理内存和2G交换空间。 堆大小(xms和xmx)之前被设置为3G,并且服务器工作正常。 由于我仍然看到很多空闲的内存,性能不佳,我将堆大小增加到7G,然后再次进行负载testing。 这次我观察到物理内存很快就被吃掉了,系统开始消耗交换空间。 后来,tomcat在用完swap之后崩溃了。 我在启动tomcat时包含了-XX:+HeapDumpOnOutOfMemoryError ,但是我没有得到任何堆转储。 当我检查/var/log/messages ,我看到kernel: Out of memory: Kill process 2259 (java) score 634 or sacrifice child

为了提供更多的信息,这里是我从Linux top看到的命令,当堆大小设置为3G和7G

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) 

所以我的问题是:

  1. 为什么会发生这个问题? 当JVM内存不足时,为什么没有引发OutOfMemoryError? 为什么直接使用交换?
  2. 为什么top RES显示java正在使用5.3G内存,消耗的内存更多?

我一直在调查和寻找一段时间,仍然找不到这个问题的根源。 非常感谢!

Solutions Collecting From Web of "Tomcat进程在交换空间不足后被Linux内核杀死; 不要得到任何JVM OutOfMemory错误"

为什么会发生这个问题? 当JVM内存不足时,为什么没有抛出OutOfMemoryException?

这不是JVM的内存不足。 主机操作系统已经耗尽了与内存相关的资源,并且正在采取激烈的行动 。 操作系统无法知道当被告知“否”,以响应更多的内存请求时,进程(在这种情况下是JVM)能够有序地关闭。 它必须杀死一些东西,否则存在整个操作系统挂起的严重风险。

无论如何,你没有看到OOME的原因是这不是一个OOME的情况。 实际上,JVM 已经被操作系统给予了太多内存,无法收回。 这是操作系统必须通过强力处理来处理的问题。

为什么直接使用交换?

它使用交换,因为整个系统的总虚拟内存需求不适合物理内存。 这是UNIX / Linux操作系统的NORMAL行为。

为什么顶级RES显示java使用的是5.3G内存,消耗的内存更多

RES号码可能有点误导。 他们所指的是进程正在使用的物理内存的数量……排除与其他进程共享或可共享的内容。 VIRT号码与您的问题更相关。 它说你的JVM使用了10.4g的虚拟内存……这比系统上可用的物理内存更多


正如另一个答案所说,它涉及到你没有得到一个OOME。 即使你确实得到了一个,对它做任何事情都是不明智的 。 OOME可能会对您的应用程序/容器造成附带损害 ,这些损坏很难发现,难以恢复。 这就是为什么OOME是一个Error不是Exception


建议:

  • 不要试图使用比物理内存更多的虚拟内存,特别是对于Java。 当一个JVM运行一个完整的垃圾回收时,它将以随机顺序多次触及其大部分 VM页面。 如果你的内存过度分配,这很容易造成整个系统的性能崩溃。

  • 请增加系统的交换空间。 (但是这可能没有帮助…)

  • 不要试图从OOME中恢复。

您可能在同一台计算机上也有使用内存的其他进程。 它看起来像你的Java进程达到5.3GB左右,机器绝望地出内存和交换。 (其他进程可能使用12GB-5.3GB = 6.7GB)所以你的Linux内核牺牲你的Java进程来保持其他进程的运行。 Java内存限制永远不会达到,所以你没有得到一个OutOfMemoryException。

考虑你需要在整个机器上运行的所有过程,并相应地调整Xmx设置(足以为所有其他进程留出空间)。 也许5GB?

在任何情况下,计数OutOfMemoryExceptions被传递是一个非常糟糕的代码味道。 如果我记得正确的话,即使只有一个OutOfMemoryException,也可能会使JVM处于“all-bets-off-off”状态,并且可能应该重新启动以避免变得不稳定。