假设问题是 OOM 杀手,那么它就会杀死你的进程,拼命地试图让操作系统在严重的内存短缺危机中保持正常运行。
我的结论是:
我会尝试添加更多交换空间,以便操作系统可以在紧急情况下交换应用程序的部分内容。
或者,减小 JVM 的堆大小。
请注意,“-Xmx ...”设置最大堆大小,而不是 JVM 可以使用的最大内存量。 JVM 将一些东西放在堆之外,包括线程堆栈的内存和应用程序正在使用的内存映射文件。
系统日志证实它是 OOM 杀手。
链接的系统日志以什么方式这么说?
它是这样说的:
Nov 15 13:53:49 ip-10-71-94-36 kernel: [3707038.606133] Out of memory: kill process 6368 (run.sh) score 4747288 or a child
Nov 15 13:53:49 ip-10-71-94-36 kernel: [3707038.606146] Killed process 9359 (java)
控制台说java被杀死了,而不是它退出了。
正确的。它被操作系统的 OOM 杀手杀死了。
如果内存不足,它通常会抛出 OutOfMemory 异常,但事实并非如此。
如果您填满了 Java 堆,就会发生这种情况。
这不是这里发生的事情。实际问题是没有足够的物理 RAM 来容纳 Java 堆。 OOM 杀手会处理它......
我正在运行如此巨大的堆,因为我需要存储数百万个对象,每个对象都需要几千字节的 RAM。
不幸的是,您尝试使用的 RAM 远多于系统可用的 RAM。这会导致虚拟内存崩溃,影响整个操作系统。
当系统开始严重抖动时,OOM 杀手(而不是 JVM)会将您的 Java 进程识别为问题的原因。然后它会杀死它(使用 SIGKILL)以保护系统的其余部分。如果没有,则存在整个系统完全锁定并需要硬重启的风险。
最后,你说:
我的盒子有 35.84 GB RAM ...
这是一个相当奇怪的值。 32 GiB 是 34,359,738,368 字节或 34.35 GB。
但基于这一点和观察到的行为,我怀疑那是可用的虚拟内存而不是物理 RAM。或者,您的“盒子”可以是在虚拟机管理程序级别启用 RAM 过度使用的虚拟机。