如果Java有垃圾收集,那为什么会出现OutOfMemoryError?

时间:2013-06-25 02:19:58

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

这是一个理论问题。我只是好奇,如果Java有一个垃圾收集机制来释放内存,那么为什么还会出现OutOfMemoryError

我搜索了SO,但可以获得这些链接

Is the garbage collector guaranteed to run before Out of Memory Error?

Garbage collection before OutOfMemoryError

这些不具体回答我的问题。如果Java通过使用垃圾收集很好地允许内存,那么OutOfMemoryError为什么会出现?

7 个答案:

答案 0 :(得分:12)

如果内存中的所有对象都不符合垃圾回收的条件,则可能发生OutOfMemoryError。例如:

List<MyClass> hellos = new ArrayList<>();
for (;;) {
   hellos.add(new MyClass());
}

这将创建一个列表并继续向其添加MyClass个对象,直到内存耗尽。没有任何对象符合垃圾收集的条件,因为它们都引用了所有对象。

答案 1 :(得分:3)

也可以以您不期望的方式隔离内存。请考虑以下字符串示例。

char[] chars      = new char[10_000_000];  // May need to adjust.
String string     = new String(chars);
chars             = null;
String substring  = string.substring(5_000_000);
string            = null; 

可以收集chars数组。可能无法收集string内的数组,因为substring包含对内部数组的引用,后跟偏移量和范围。因此,仍然分配10个 7 字符,即使只使用5 * 10 6 并且可以访问。

Java 1.7.0_06

String.substring似乎不再有这种行为。在Java Performance Tuning Guide web site的一篇文章中,Mikhail Vorontsov报告说,在Java 1.7.0_06及更高版本中,String.substring始终创建一个独立于旧String的新Stringoffset类不再具有rangechar[]个实例变量。创建一个大字符串,获取子字符串并丢弃原始字符串不会使旧字符串// Java 1.7.0_06 and up char[] chars = new char[10_000_000]; // May need to adjust. String string = new String(chars); chars = null; String substring = string.substring(5_000_000); // Copies a portion of string's array to a new array. string = null; // string's array is no longer reachable, and may be garbage collected. 隔离。

{{1}}

答案 2 :(得分:2)

因为并非所有记忆都是垃圾。

答案 3 :(得分:1)

垃圾收集器可以处理不会被使用的内存。

但是,如果你分配内存,并且该内存在范围内,这意味着,垃圾收集器无法真正清理该内存。

当分配的内存太高于VM允许的内存时,就会出现异常。

答案 4 :(得分:1)

无法收集仍在运行代码中引用它的对象。因此,如果有一种理论上甚至可以访问对象的方法,它就会卡在内存中。

正如所说的那样,Java并没有消除关心内存的需要;它只是自动化了很多内存管理的东西。你仍然必须尽自己的一份力量,以确保你的生命周期结束后你不会躲开物体...因为只要它们可以到达(无论间接地),它们就会占用无法回收的记忆

答案 5 :(得分:0)

最好在使用它们完成工作后使对象无效,这样就可以确保垃圾收集器可以使用这些对象,以避免内存不足或内存泄漏等问题。

答案 6 :(得分:0)

如果内存不足且没有变量或对象可以删除,则会引发除外。

使用GC(垃圾收集)的最佳方法是:

如果不再使用该变量,则将该变量显式指定为空值。