OutOfMemoryError - 为什么等待的Thread不能被垃圾收集?

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,但这没有帮助.

Rob*_*bin 8

线程是顶级对象.它们是"特殊的",因此它们不遵循与其他对象相同的规则.不依赖引用来保持它们"活着"(即从GC中安全).线程在结束之前不会收集垃圾.由于线程被阻止,因此您的示例代码中不会发生这种情况.当然,既然线程对象没有被垃圾收集,那么它引用的任何其他对象(在你的情况下是队列)也不能被垃圾收集.


bru*_*nde 5

您无限期地创建线程,因为它们都会阻塞,直到ArrayBlockingQueue<Integer> abq有一些条目.所以最终你会得到一个OutOfMemoryError.

(编辑)

您创建的每个线程永远不会结束,因为它会阻塞直到abq队列为一个条目.如果线程正在运行,则GC不会收集线程引用的任何对象,包括队列abq和线程本身.