这是一个理论问题。我只是好奇,如果 Java 有一种垃圾收集机制来释放内存,那为什么还会OutOfMemoryError
发生呢?
我搜索了这个,但可以获得这些链接
这些并没有具体回答我的问题。如果 Java 通过使用垃圾收集来很好地允许内存,那么为什么会OutOfMemoryError
发生呢?
这是一个理论问题。我只是好奇,如果 Java 有一种垃圾收集机制来释放内存,那为什么还会OutOfMemoryError
发生呢?
我搜索了这个,但可以获得这些链接
这些并没有具体回答我的问题。如果 Java 通过使用垃圾收集来很好地允许内存,那么为什么会OutOfMemoryError
发生呢?
如果内存中没有对象符合垃圾回收条件,则可能发生 OutOfMemoryError。例如:
List<MyClass> hellos = new ArrayList<>();
for (;;) {
hellos.add(new MyClass());
}
这将创建一个列表并不断向其中添加MyClass
对象,直到内存耗尽。没有一个对象符合垃圾回收的条件,因为它们都有对它们的引用。
也可以以您意想不到的方式隔离内存。考虑以下字符串示例。
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个字符。
似乎String.substring
不再有这种行为。在Java Performance Tuning Guide 网站的一篇文章中,Mikhail Vorontsov 报告说,在 Java 1.7.0_06 及更高版本中,String.substring
总是创建一个String
独立于旧版本的新版本。该类String
不再具有offset
实例range
变量。创建一个大字符串、获取子字符串并丢弃原始字符串不会留下旧字符串的char[]
隔离。
// 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.
因为并非所有内存都是垃圾。
垃圾收集器在不会被使用的内存上工作。
但是,如果您分配内存,并且该内存在范围内,则意味着垃圾收集器无法真正清理该内存。
当分配的内存高于 VM 允许的内存时,就会出现该异常。
无法收集仍然从运行代码中引用它的对象。因此,如果有一种方法可以在理论上访问一个对象,它就会被卡在内存中。
就是这么说的,Java 并没有消除关心内存的需要。它只是自动化了很多内存管理的东西。您仍然必须尽自己的一份力量,以确保您不会在对象的使用寿命结束后将其扔掉......因为只要它们可以到达(但间接地),它们就会占用无法回收的内存.
最好在您的工作完成后将您的对象无效化,这样您就可以确保垃圾收集器可以使用这些对象,以避免出现内存不足或内存泄漏的问题。
如果内存不足并且没有适合删除的变量或对象,则会引发 except。
所以使用 GC(垃圾收集)的最佳方式是:
如果不再使用该变量,则将其显式分配为空值。