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

bag*_*wen 13 java linux memory performance tomcat

我正在对tomcat服务器执行负载测试.服务器具有10G物理内存和2G交换空间.堆大小(xms和xmx)之前设置为3G,服务器工作正常.由于我仍然看到很多可用内存并且性能不佳,我将堆大小增加到7G并再次运行负载测试.这次我观察到物理内存被很快吃掉了,系统开始消耗交换空间.后来,tomcat在耗尽交换空间后崩溃了.我-XX:+HeapDumpOnOutOfMemoryError在启动tomcat时包含,但我没有得到任何堆转储.当我查看时/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
    
    Run Code Online (Sandbox Code Playgroud)
  • 启动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
    
    Run Code Online (Sandbox Code Playgroud)
  • 开始加载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
    
    Run Code Online (Sandbox Code Playgroud)

xms&xmx = 7G(导致tomcat崩溃):

  • 在启动tomcat之前:

    Mem:  10129972k total,  1270348k used,  8859624k free,    98504k buffers
    Swap:  2097144k total,        0k used,  2097144k free,    74656k cached
    
    Run Code Online (Sandbox Code Playgroud)
  • 启动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
    
    Run Code Online (Sandbox Code Playgroud)
  • 开始加载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
    
    Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

Tomcat版本:

6.0.36
Run Code Online (Sandbox Code Playgroud)

Linux服务器:

Red Hat Enterprise Linux Server release 6.4 (Santiago)
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  1. 为什么会出现这个问题?当JVM内存不足时,为什么没有抛出OutOfMemoryError?为什么它直接使用交换?
  2. 为什么top RES表明java正在使用5.3G内存,消耗的内存要多得多?

我一直在调查和搜索一段时间,仍然找不到这个问题的根本原因.非常感谢!

Ste*_*n C 9

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

它不是JVM耗尽内存.它是主机操作系统已经耗尽内存相关的资源,并正在采取过激行动.操作系统无法知道进程(在这种情况下是JVM)能够在响应更多内存请求而被告知"否"时以有序方式关闭.它必须硬杀东西,否则整个操作系统都会有严重的风险.

无论如何,你没有看到OOME的原因是这不是OOME的情况.实际上,操作系统已经为JVM 提供了太多内存,并且没有办法将其收回.这就是操作系统必须通过硬杀死进程来解决的问题.

为什么它直接使用交换?

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

为什么top RES显示java正在使用5.3G内存,消耗的内存要多得多

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


正如另一个答案所说的那样,有人担心你没有得到OOME.即使你确实得到了一个,用它做任何事都是不明智的.OOME可能会对您的应用程序/容器造成附带损害,这种损坏难以检测并且难以恢复.这就是为什么OOME Error不是Exception.


建议:

  • 不要尝试使用比物理内存多得多的虚拟内存,尤其是Java.当JVM运行完整的垃圾收集时,它将以随机顺序多次触摸其大多数 VM页面.如果您的内存占用过多,则可能会导致抖动,从而导致整个系统的性能下降.

  • 增加系统的交换空间.(但那可能没有用......)

  • 不要试图从OOME恢复.