【问题标题】:Why isn't OutOfMemoryError reproduced with a Collection of Object?为什么 OutOfMemoryError 不与对象集合一起重现?
【发布时间】:2018-03-04 13:36:00
【问题描述】:

我正在尝试使用此代码重现 OutOfMemoryError

List<Object> objects = new LinkedList<>();
while (true)
    objects.add(new Object());
}

但它实际上从来没有发生过,我使用了 -Xmx512,而 JVM 每次只占用大约 497 MB,然后没有消耗内存。

我用的是 jdk1.8.0_151

谁能帮我弄清楚为什么没有抛出错误?

【问题讨论】:

  • 在添加 println 时,您是否真的检查了第二行是否在循环块内?
  • @Am_I_Helpful 是的,是的

标签: java garbage-collection jvm out-of-memory


【解决方案1】:

您没有得到java.lang.OutOfMemoryError,因为您正在创建非常小的对象(new Object())并且您指定的堆大小非常大。如果您想查看 OOM,则:

  • 你使用了小对象new Object() + 像Xmx64 这样的小堆大小
  • 您创建了一些重对象,例如 Calendar (objects.add(Calendar.getInstance());) + Xmx512

使用new Object() + Xmx512,您将不得不等待很长时间才能获得OOM。

关于你无法访问的代码错误,我想你已经发现你遇到了括号问题,如果你这样做,那么你不会得到那个编译错误,但是如果你在 WHILE 循环之后放置任何语句,那么你会得到那个错误。

    while (true){
        objects.add(Calendar.getInstance());
        System.out.println(objects);
    }

【讨论】:

  • 我稍微修改了代码,我花了 11420584 个对象才产生错误,谢谢!
【解决方案2】:

编译器可能会消除此代码,因为它被认为是死代码并且根本不执行它。

尝试在循环内部引入诸如打印语句之类的副作用。

【讨论】:

  • 好吧,我的想法是稍后在循环中为这些对象添加一些操作,但由于某种原因代码无法访问
【解决方案3】:

相当简单(在 IntelliJ IDEA 中执行):

public class Foo {

    public static void main(String[] argv) throws IllegalAccessException {

        Collection<byte[]> data = new ArrayList<>();
        for (;;) {
            data.add(new byte[1000]);
        }

    }
}

线程“主”java.lang.OutOfMemoryError 中的异常:Java 堆空间 在 Foo.main(Foo.java:15)

进程以退出代码 1 结束

【讨论】:

  • 是的,但这不是我想要的。显然,这样大小的数组不会有足够的连续空间,但对于小对象,它似乎并没有那样工作
  • 刚试了1000个一样的效果,1Kb也不算大对象吧?
  • 相对于单个Object的大小,其实还是蛮大的
  • 您没有在问题中指定它必须是new Object(),如果不一起优化,这是一个非常无用的结构。你想达到什么目的?您想在 OOME 之后检查恢复,这应该已经足够了。
  • 我想了解为什么在这种特殊情况下没有抛出错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 2010-09-19
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 1970-01-01
  • 2018-04-03
相关资源
最近更新 更多