OutOfMemoryError - why waiting for a thread will not collect garbage?

This simple code example demonstrates the problem. I create ArrayBlockingQueueand a thread waiting for data in this queue using take(). After the cycle is completed, theoretically, both the queue and the stream can be garbage collected, but in practice I will soon get it OutOfMemoryError. What prevents it from being GC'd, and how can it be fixed?

/**
 * 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();
        }
    }
}

I am using Java 1.6.0.

UPDATE: execute GC after several iterations, but this does not help.

+5
source share
7 answers

- . "", , . , "" ( GC). , . , . , , , , ( ), .

+8

, , ArrayBlockingQueue<Integer> abq . OutOfMemoryError.

()

, abq . , GC - , , abq .

+5
abq.put(0);

.

take(), .

+2

, , .

, . , , ( , ), GC OutOfMemoryException.

. , , .

0

while . , , .

abq, while?

. System.gc() GC. .

take() " , , ". , ArrayBlockingQueue, , , OOM.

0

, Java, , : , GC , , , GC , .

, , , , java.util.concurrent, , , .

0

System.gc , . , , , . , .

while (true) {
    // just a simple demo, not useful code.
    // 0 0 - the first number is thread reference count, the second is abq ref count
    final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
    // 0 1
    final Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                abq.take();
                // 2 2
            } catch (final InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    // 1 1
    t.start();
    // 2 2 (because the run calls abq.take)
    // after end of loop
    // 1 1 - each created object reference count is decreased
}

- , , t - , abq.take? run abq , GC , .

, . Java , , , Runnable. , abq, run, , .

0

All Articles