【问题标题】:JVM Out of Memory CausesJVM内存不足原因
【发布时间】:2020-12-09 08:30:57
【问题描述】:

问题基于 Oracle Hotspot JDK8。

当应用程序遇到java.lang.OutOfMemory: Java heap space 异常时,我想,有两个可能的原因。

  1. 分配的 JVM 堆大小达到-Xmx 指定大小,GC 系统无法挤出足够的空间。
  2. 分配的 JVM 堆未达到-Xmx,但没有足够的物理内存供 JVM 堆增长。假设-Xms -Xmx。

我知道1 是JVM 抛出java.lang.OutOfMemory: Java heap space 异常的原因。 2 是一个合理的原因吗?

我发现some articles 提到了java.lang.OutOfMemoryError: native memory exhausted,但它们都仅限于IBM 网站。 此扩展仅限于 IBM 实现的 JVM 还是 JVM 规范中的标准扩展?


我用@Eugene 提供的代码做了一些实验。正如@Holger 所指出的,结果因环境而异。我使用 Hotspot JDK8 x64 在 CentOS x64 和 Win7 x64 上进行了测试。 为简单起见,已禁用交换和虚拟内存。

我逐步增加内存限制(-Xmx 和 -Xms)。

我。 -Xmx 可用的逻辑内存

  • 在 CentOS 和 Windows 上都显示 OutOfMemoryError: Java heap space

二。 可用逻辑内存 最大物理内存

  • CentOS:GC 多次尝试 Full GC,Allocation Failure,进程被系统杀死,并留下消息Killed
  • Windows:GC 多次尝试 Full GC,Allocation Failure,并抛出 OutOfMemoryError: Java heap space

三。 -Xmx > 最大物理内存

  • CentOS:与 II 相同
  • Windows:与 II 中相同

四。 -Xms > 最大物理内存

  • CentOS:JVM 似乎无法启动。错误信息如下:

Java HotSpot(TM) 64 位服务器虚拟机警告:INFO: os::commit_memory(0x00000000e62a0000, 349569024, 0) 失败; error='无法分配内存' (errno=12)

  • Windows:JVM 无法启动。错误信息如下:

虚拟机初始化过程中发生错误 无法为对象堆保留足够的空间


因此,相同的 JVM 在不同的操作系统中表现不同。

  • 在 Windows 上,操作系统不会杀死 JVM。并且当内存使用增长超过时,JVM总是抛出OutOfMemoryError: Java heap space
  • 在 Linux 上,当内存不足时,操作系统会终止进程。
  • 在两个操作系统上,当可用内存不能满足 JVM 最低要求时,JVM 无法启动。

【问题讨论】:

  • 你为什么不试试看看会发生什么?将-Xmx 设置为超过您计算机上的虚拟空间,然后运行一个分配空间的程序,直到它终止。 --- 提示: 在虚拟机或 Docker 中运行它可能更容易,您可以更好地控制“机器”有多少内存。
  • 这取决于特定环境(包括JVM实现)a)-Xmx是否需要物理内存(而不是逻辑内存/交换空间)和b)它允许指定比系统更多的最大内存可以处理。甚至还有那个臭名昭著的 Linux 内存过度使用特性,即它保证了内存的可用性,因为分配请求永远不会失败,但它只是在内存不足时随机杀死进程。
  • @Holger 我记得-Xmx,目前,将“提交”那么多内存,但还没有驻留。至于第(2)点:每个处理容器的java人员,尤其是kubernetes都应该意识到这种突然死亡,特别是因为它不支持swap。优秀的 cmets。
  • @Andreas 我试过了,它似乎在情况 2 中被系统杀死了

标签: java jvm


【解决方案1】:

首先,正如您问题下的评论所解释的那样,GC 因“内存不足”而失败的原因更多。

证明点号 (2) 很简单,只需创建一些始终分配的代码:

public static void main(String[] args) {
    test(1);
}

static void test(int x){
    List<byte[]> list = new ArrayList<>();
    while(x == 1){
        byte [] b =new byte[1 * 1024 * 1024];
        b[100] = 42;
        list.add(b);
    }

    System.out.println(list.hashCode());
}

并在内存少于100g 的系统上使用-Xms1g -Xmx100g 运行它。您可以启用 GC 日志(例如,我在 java-9 标志中使用 "-Xlog:heap*=debug" "-Xlog:gc*=debug")并查看 GC 是如何努力应对这种不断分配的,最终失败。

【讨论】:

  • 我在 CentOS 上用 JDK8 试过(换掉)。当 -Xmx 大于物理内存并且 JVM 消耗所有可用内存时,它会被系统杀死,只留下一条消息 Killed。那么它是否证明我它显示 OutOfMemoryError:Java heap space,它不可能是原因 2?
  • @SuN 很有趣。在我的 Mac 上,它因 OOM 而死。你有没有在容器中运行它?
  • 不,我在 VirtualBox 中使用 CentOS 和 Windows 7 作为来宾操作系统运行测试。更多详细信息列在问题描述第二部分实验中。
  • @SuN 完全正确。您通过 VirtualBox 在虚拟化容器中运行。你所看到的几乎是意料之中的。
猜你喜欢
  • 2011-08-03
  • 2014-05-12
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2012-12-14
相关资源
最近更新 更多