当前位置: 首页 > 知识库问答 >
问题:

Tomcat进程在交换空间用完后被Linux内核杀死;不获取任何JVM OutOfMemory错误

越雨泽
2023-03-14

我正在对tomcat服务器进行负载测试。服务器具有10G物理内存和2G交换空间。堆大小(xms和xmx)以前设置为3G,服务器工作正常。由于我仍然看到剩余的空闲内存很多,而且性能不好,所以我将堆大小增加到7G,并再次运行负载测试。这一次,我观察到物理内存很快就被耗尽了,系统开始消耗交换空间。后来,tomcat在交换空间用完后崩溃。启动tomcat时,我包括了-XX:HeapDumpOnOutOfMemoryError,但我没有得到任何堆转储。当我检查/var/log/messages时,我看到了内核:内存不足:杀死进程2259(java)得分634或牺牲子进程。

为了提供更多信息,以下是当堆大小设置为3G和7G时,我从Linuxtop命令中看到的内容

xms

>

  • 启动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

    >

  • 启动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. 为什么topRES显示java使用的是5.3G内存,消耗的内存要多得多?

    我已经调查和寻找了一段时间,仍然找不到这个问题的根本原因。非常感谢!


  • 共有2个答案

    勾渝
    2023-03-14

    同一台计算机上可能有其他进程也使用内存。看起来你的java进程在机器极度耗尽内存和交换之前达到了5.3GB左右。(其他进程可能使用12GB-5.3GB=6.7GB)所以你的linux内核牺牲了你的java进程来保持其他进程的运行。java内存限制永远不会达到,所以你不会得到OutOfMemoryException。

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

    无论如何,计算正在传递的OutOfMemoryExceptions是一种非常糟糕的代码气味。如果我没记错的话,即使获得一个OutOfMemoryException也会使JVM处于“全部关闭”状态,并且可能应该重新启动以避免变得不稳定。

    华甫
    2023-03-14

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

    内存溢出的不是JVM,而是主机操作系统内存溢出相关的资源,并且正在采取激烈的行动。操作系统无法知道进程(在本例中是JVM)在响应更多内存请求时被告知“否”时能够有序关闭。它必须硬杀死某些东西,否则整个操作系统就有挂起的严重风险。

    不管怎么说,你没有看到臭味的原因是这不是一个臭味的情况。实际上,操作系统已经给JVM提供了太多的内存,无法收回。这是操作系统必须通过硬杀死进程来解决的问题。

    为什么它直接使用交换?

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

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

    RES数字可能有点误导。它们指的是进程当前使用的物理内存量...不包括与其他进程共享或可共享的东西。VIRT数字与您的问题更相关。它说您的JVM正在使用10.4g的虚拟...这比您系统上可用的物理内存多。

    正如另一个答案所说,你担心你没有得到一个OOME。即使你真的得到了一个,用它做任何事情都是不明智的。OOME可能会对你的应用程序/容器造成附带损害,这种损害很难检测到,也更难恢复。这就是为什么OOME是一个错误而不是一个异常

    建议:

    >

  • 不要试图使用比物理内存多得多的虚拟内存,尤其是Java。当JVM运行完整的垃圾收集时,它将以随机顺序多次接触其大部分VM页面。如果内存分配过多,则很容易导致抖动,从而降低整个系统的性能。

    一定要增加系统的交换空间。(但这可能没有帮助……)

    不要试图从臭气中恢复过来。

  •  类似资料:
    • 问题内容: 如何杀死linux中最后一个生成的后台任务? 例: 问题答案: bash中有一个特殊的变量: $!扩展为在后台执行的最后一个进程的PID。

    • 问题内容: 当Linux内存不足(OOM)耗尽时,OOM杀手根据一些启发式方法选择一个要杀死的进程(这很有趣: http //lwn.net/Articles/317814/)。 如何以 编程方式 确定OOM杀手最近杀死了哪些进程? 问题答案: 试试看:

    • 问题内容: 我正在服务器上运行一个nohup进程。当我尝试杀死它时,我的油灰控制台会关闭。 这是我尝试查找进程ID的方法: 这是杀死的命令 问题答案: 使用并将任务放在后台时,后台运算符()将在命令提示符下为您提供PID。如果您的计划是手动管理该进程,则可以保存该PID,然后在需要时通过或(如果需要强制终止)将其用于终止该进程。或者,您可以稍后找到PID,然后从那里找到PID。请注意,关键字/命令

    • 我正试图通过后台获取从url获取数据。My func尝试获取数据,如果有新数据,它会发送本地通知。当我最小化应用程序时,背景提取在大约10-20分钟后工作。但当我关闭应用程序(双击home按钮并关闭应用程序)时,它就不起作用了。我等了大约一个小时,但没有成功。我正在Android系统中使用后台服务,它正在成功运行。当应用程序关闭时,有没有办法从url获取数据并发送本地通知?我使用的是Xcode 6

    • 错误: 内存不足,Java运行时环境无法继续。本机内存分配(mmap)无法映射71827456字节以提交保留内存。可能的原因:系统在32位模式下没有物理RAM或交换空间,遇到了进程大小限制。可能的解决方案:减少系统上的内存负载增加物理内存或交换空间检查交换备份存储是否已满在64位OS上使用64位Java减少Java堆大小(-xmx/-xms)减少Java线程数量减少Java线程堆栈大小(-xs)设

    • 问题内容: 我从python脚本生成了5个不同的进程,如下所示: 我的问题是,当父进程(主脚本)以某种方式被杀死时,子进程继续运行。 当父进程被杀死时,有没有办法杀死这样生成的子进程? 编辑:我正在尝试: 但这似乎不起作用 问题答案: 我自己也遇到了同样的问题,我有以下解决方案: 打电话之前,您可以设置。然后如此处所述python.org multiprocessing 进程退出时,它将尝试终止其