OutOfMemoryError
?我在SO上搜索了这个问题,但只找到了以下链接Is the garbage collector guaranteed to run before Out of Memory Error?和Garbage collection before OutOfMemoryError。它们并没有直接回答我的问题。如果Java通过使用垃圾回收如此好地管理内存,那么为什么还会出现OutOfMemoryError
?OutOfMemoryError
?我在SO上搜索了这个问题,但只找到了以下链接Is the garbage collector guaranteed to run before Out of Memory Error?和Garbage collection before OutOfMemoryError。它们并没有直接回答我的问题。如果Java通过使用垃圾回收如此好地管理内存,那么为什么还会出现OutOfMemoryError
?如果内存中没有任何对象符合垃圾收集条件,就会发生OutOfMemoryError错误。例如:
List<MyClass> hellos = new ArrayList<>();
for (;;) {
hellos.add(new MyClass());
}
这会创建一个列表,并持续将MyClass
对象添加到其中,直到内存耗尽。由于所有这些对象都有引用,因此没有一个对象符合垃圾回收的条件。
OutOfMemoryError
错误,循环只需要运行足够长的时间来占用所有内存空间,不需要无限循环。 - Prasad Kharkar有时候,内存会以出乎意料的方式被隔离。请考虑以下字符串示例。
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
数组可能会被收集。由于substring
包含对内部数组的引用,后跟其偏移量和范围,因此string
内部的数组可能不会被收集。因此,即使仅使用和访问5 * 10 6个字符,也仍然保留了107个字符。
似乎String.substring
不再具有这种行为。在Java Performance Tuning Guide web site的一篇文章中,Mikhail Vorontsov报告说,在Java 1.7.0_06及更高版本中,String.substring
始终创建一个新的String
,独立于旧的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.
string
是不可变的,所以不会有任何更改其内容的操作。 因此,JVM可以安全地使substring
重用string
内部的char[]
。 然后,当将string
设置为null时,除了数组本身之外,string
内的所有变量都可以被收集; substring
引用它。 - Eric Jablow因为并不是所有的内存都是垃圾。
如果一个对象仍然被运行代码引用,它就不能被回收。因此,如果有一种即使理论上也可以访问对象的方法,它就会占用内存。
顺便说一句,Java并没有消除关注内存的需要;它只是自动化了很多内存管理工作。你仍然需要尽自己的一份力来确保在对象的有用寿命结束后不会将它们藏起来……因为只要它们可以被访问(无论多么间接),它们就会占用无法被回收的内存。
在完成对象的工作后最好将其置空,以确保对象可供垃圾收集器使用,避免出现内存不足或内存泄漏等问题。
null
通常是完全浪费时间的。方法局部引用无论如何都会超出范围,而作为实例变量的引用在任意时间设置为 null 并不容易,除非它们真的应该是局部变量,在这种情况下它们也会超出范围... - user207421如果你的内存用尽了,而且没有任何可以删除的变量或对象,那么就会引发异常。
因此,使用垃圾回收(Garbage collection)的最佳方法是:
如果某个变量不再使用,请显式地将其赋值为 null 值。