mar*_*nus 5 java multithreading garbage-collection out-of-memory
这个简单的示例代码演示了该问题.我创建了一个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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我使用的是Java 1.6.0.
更新:在几次迭代后执行GC,但这没有帮助.
线程是顶级对象.它们是"特殊的",因此它们不遵循与其他对象相同的规则.不依赖引用来保持它们"活着"(即从GC中安全).线程在结束之前不会收集垃圾.由于线程被阻止,因此您的示例代码中不会发生这种情况.当然,既然线程对象没有被垃圾收集,那么它引用的任何其他对象(在你的情况下是队列)也不能被垃圾收集.
您无限期地创建线程,因为它们都会阻塞,直到ArrayBlockingQueue<Integer> abq有一些条目.所以最终你会得到一个OutOfMemoryError.
(编辑)
您创建的每个线程永远不会结束,因为它会阻塞直到abq队列为一个条目.如果线程正在运行,则GC不会收集线程引用的任何对象,包括队列abq和线程本身.