この簡単なサンプルコードは、この問題を示しています。 ArrayBlockingQueue
を作成し、take()
を使用してこのキューのデータを待機するスレッドを作成します。ループが終了すると、理論的にはキューとスレッドの両方がガベージコレクトされますが、実際にはすぐにOutOfMemoryError
が返されます。これをGCにすることを妨げているのは何ですか?これをどのように修正できますか?OutOfMemoryError - 待機中のスレッドがガベージコレクトされないのはなぜですか?
/**
* 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を使用しています。
UPDATE:数回反復してGCを実行しますが、これは役に立ちません。
スレッドごとにSystem.gc()を実行しても、スレッドは破棄されません。 – martinus
@martinusもっと慎重に読んでください。スレッドのガベージコレクションにかかる時間は、スレッドの作成に要する時間よりも長くなります。あなたが止められていないバスタブを満たすのを開始し、あなたが水を浴槽の排水口よりも速く加えると、浴槽は最終的に満杯になりオーバーフローします。これは、リソースの割り当て/解放の競合状態です。 100スレッドしか作成せずにwhileループを続けるとどうなりますか?スレッドは最終的に収集されますか? – Wedge
@wedge、いいえ、彼らは収集されていません!または何か他のことをする。各ループの終わりに1秒待っても、GC'dは何もありません。 – martinus