Mã mẫu đơn giản này chứng tỏ sự cố. Tôi tạo một ArrayBlockingQueue
và một luồng chờ dữ liệu trên hàng đợi này bằng cách sử dụng take()
. Sau khi vòng lặp kết thúc, trên lý thuyết cả hàng đợi và luồng có thể được thu thập rác, nhưng trong thực tế, tôi sớm nhận được một số OutOfMemoryError
. Điều gì ngăn cản điều này là GC'd, và làm thế nào điều này có thể được sửa?OutOfMemoryError - tại sao Chủ đề chờ đợi không được thu gom rác?
/**
* 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();
}
}
}
Tôi đang sử dụng Java 1.6.0.
CẬP NHẬT: thực hiện GC sau một vài lần lặp, nhưng điều này không giúp ích gì.
Tôi không nghĩ đó là vấn đề, ngay cả khi tôi chạy System.gc() trong mỗi vòng lặp, các chuỗi không bị hủy. – martinus
@martinus đọc kỹ hơn. Lượng thời gian cần để thu gom rác dài hơn thời gian cần thiết để tạo chủ đề. Nếu bạn bắt đầu làm đầy bồn tắm không bị cản trở và bạn thêm nước nhanh hơn ống dẫn nước, bồn tắm cuối cùng sẽ lấp đầy và tràn. Đó là điều kiện phân bổ tài nguyên/phân bổ deallocation. Điều gì sẽ xảy ra nếu bạn chỉ tạo 100 chuỗi và tiếp tục trong vòng lặp while? Các chủ đề có được thu thập cuối cùng không? – Wedge
@ wedge, không, họ không bao giờ được thu thập! hoặc làm điều gì đó khác. Ngay cả khi tôi đợi một giây ở cuối mỗi vòng lặp thì không có gì là GC. – martinus