如何在Linux JVM 64位上引发OutOfMemoryError错误

3

在我的单元测试中,我故意尝试引发一个OutOfMemoryError异常。我使用了类似以下的简单语句:

byte[] block = new byte[128 * 1024 * 1024 * 1024];

这段代码在Win7 64位系统上,使用jdk6u21 64位版本能够正常运行。但是当我在Centos 5 64位系统上,使用相同的jdk6u21版本运行时,即使我将数组大小扩大,也没有抛出OutOfMemoryError异常。

有什么想法吗?

7个回答

5

Linux不总是立即分配您请求的所有内存,因为许多实际应用程序要求比它们需要的更多。这称为超额承诺(它也意味着有时会猜错,然后可怕的OOM killer会袭击)。

对于您的单元测试,我只会手动抛出OutOfMemoryError


我真的很想发布一个仅包含throw new OutOfMemoryError();的答案,但现在没有意义了... +1 - David Z
抱歉,也许我表达不够清楚。我不想简单地抛出OOM(Out Of Memory)异常,而是想将内存耗尽直至枯竭。这是因为我正在测试软引用的内存使用情况。 - Gilbeg

4

如果您只想使用所有内存,请按照以下步骤操作:

    try {
        List<Object> tempList = new ArrayList<Object>();
        while (true) {
            tempList.add(new byte[128 * 1024 * 1024 * 1024]);
        }
    } catch (OutOfMemoryError OME) {
       // OK, Garbage Collector will have run now...
    }

谢谢!这个可行。 我只是把 new byte[128 * 1024 * 1024 * 1024] 改成了 new byte[Integer.MAX_VALUE]。 - Gilbeg

3

128*1024*1024*1024=0 因为 int 类型是 32 位,Java 不支持超过 4GB 的数组。


1

你可以使用-Xmx标志,故意将JVM的最大堆大小设置为一个较小的值。

运行以下程序:


public final class Test {

  public static void main(final String[] args) {
    final byte[] block = new byte[Integer.MAX_VALUE];
  }

}

使用以下JVM参数:-Xmx8m

这样就可以了:


Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at Test.main(Test.java:4)

1
ulimit -v 102400 
ulimit -d 102400
unitTest.sh

以上代码应该将您的单元测试限制在1M虚拟内存和1M数据段大小。当您达到其中任何一个时,您的进程应该得到ENOMEM错误。请注意,这些限制适用于调用它们退出的进程/ shell;您可能希望在子shell中运行它们。

有关其工作原理的详细信息,请参阅man 2 setrlimit。使用help ulimit命令了解ulimit命令。


1

虽然是小问题,但分配新的long[Integer.MAX_VALUE]会使内存使用速度快8倍。(每个约16 GB)


0
没有 OutofMemoryError 的原因是内存处于未提交状态,没有页面。
如果您在数组的每个 4K 中写入一个非零字节,那么这将导致内存被分配。

为什么每个数组要4K? 如果我用以下的字节值填充整个数组,会有什么不同吗?byte b = 10; Arrays.fill(block, b); - Gilbeg
海报假设4k块大小(据我所知是合理的)。每4k一个字节比填充整个数组更快。 - Slartibartfast

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接