这个简单的示例代码演示了这个问题。我创建了一个 ArrayBlockingQueue
,以及一个使用 take()
等待队列中数据的线程。循环结束后,理论上队列和线程都可以被垃圾回收,但实际上我很快就会得到一个OutOfMemoryError
。是什么阻止了它被 GC,如何解决?
/**
* Produces out of memory exception because the thread cannot be garbage
* collected.
*/
@Test
public void checkLeak() {
int count = 0;
while (true) {
// just a simple demo, not useful code.
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
final Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
abq.take();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
// perform a GC once in a while
if (++count % 1000 == 0) {
System.out.println("gc");
// this should remove all the previously created queues and threads
// but it does not
System.gc();
}
}
}
我正在使用 Java 1.6.0。
更新:在几次迭代后执行 GC,但这没有帮助。
最佳答案
线程是顶级对象。它们很“特殊”,因此它们不遵循与其他对象相同的规则。不依赖引用来使它们“存活”(即免受 GC 的影响)。线程在结束之前不会被垃圾回收。这不会发生在您的示例代码中,因为线程被阻塞了。当然,既然线程对象没有被垃圾回收,那么它引用的任何其他对象(在您的例子中是队列)也不能被垃圾回收。
关于java - OutOfMemoryError - 为什么等待线程不能被垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/785044/