java - OutOfMemoryError - 为什么等待线程不能被垃圾回收?

标签 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();
        }
    }
}

我正在使用 Java 1.6.0。

更新:在几次迭代后执行 GC,但这没有帮助。

最佳答案

线程是顶级对象。它们很“特殊”,因此它们不遵循与其他对象相同的规则。不依赖引用来使它们“存活”(即免受 GC 的影响)。线程在结束之前不会被垃圾回收。这不会发生在您的示例代码中,因为线程被阻塞了。当然,既然线程对象没有被垃圾回收,那么它引用的任何其他对象(在您的例子中是队列)也不能被垃圾回收。

关于java - OutOfMemoryError - 为什么等待线程不能被垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/785044/

相关文章:

Java - 如何使这些方法成为多线程?

c# - 锁定行为 Task.WaitAny 与 Task.Result

go - 为什么要在堆上存储指针语义的值?

java - jvm8 中的元空间大小是多少?

java - 出现异常.NoClassDefFoundError : com/itextpdf/text/log/CounterFactory

Java 11 模块信息 : how to register an annotation processor

java - 需要有关 Java 中字符串递归的帮助

c++ - sleep_until 过去的某个时间点

C#:垃圾收集器

java - 抛出主:NullPointerException in using CardLayout