이 간단한 샘플 코드는 문제를 보여줍니다. 나는 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을 사용하고 있습니다.
업데이트 : 몇 번의 반복 작업 후에 GC를 수행하지만 이는 도움이되지 않습니다.
각 루프에서 System.gc()를 실행해도 스레드가 파괴되지 않는다고해서 문제가되지 않는다고 생각합니다. – martinus
@martinus 더 자세히 읽으십시오. 스레드를 가비지 수집하는 데 걸리는 시간은 스레드를 만드는 데 걸리는 시간보다 깁니다. 멈추지 않은 욕조를 채우고 욕조 배수구보다 빨리 물을 넣으면 욕조가 결국 채워져 넘치게됩니다. 자원 할당/할당 해제 경쟁 조건입니다. 100 개의 스레드 만 만들고 while 루프를 계속하면 어떻게됩니까? 스레드가 결국 수집됩니까? – Wedge
@ 웨지, 아니, 그들은 수집되지 않는다! 또는 다른 것을하십시오. 각 루프가 끝날 때까지 1 초를 기다릴 때도 아무 것도 GC'd되지 않습니다. – martinus