Tôi đang cố gắng triển khai một cơ chế xóa các tệp đã lưu trong bộ nhớ cache khi các đối tượng giữ chúng chết và quyết định sử dụng PhantomReference
để nhận thông báo về việc thu thập rác của một đối tượng. Vấn đề là tôi tiếp tục gặp phải hành vi kỳ lạ của ReferenceQueue
. Khi tôi thay đổi một cái gì đó trong mã của tôi nó đột nhiên không lấy các đối tượng nữa. Vì vậy, tôi đã cố gắng để làm ví dụ này để thử nghiệm, và chạy vào cùng một vấn đề:Tại sao đối tượng của tôi không chết?
public class DeathNotificationObject {
private static ReferenceQueue<DeathNotificationObject>
refQueue = new ReferenceQueue<DeathNotificationObject>();
static {
Thread deathThread = new Thread("Death notification") {
@Override
public void run() {
try {
while (true) {
refQueue.remove();
System.out.println("I'm dying!");
}
} catch (Throwable t) {
t.printStackTrace();
}
}
};
deathThread.setDaemon(true);
deathThread.start();
}
public DeathNotificationObject() {
System.out.println("I'm born.");
new PhantomReference<DeathNotificationObject>(this, refQueue);
}
public static void main(String[] args) {
for (int i = 0 ; i < 10 ; i++) {
new DeathNotificationObject();
}
try {
System.gc();
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Đầu ra là:
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
I'm born.
Không cần phải nói, việc thay đổi thời gian sleep
, gọi gc
nhiều lần, vv không hoạt động.
CẬP NHẬT
Như đã đề cập, tôi gọi Reference.enqueue()
tham chiếu của tôi, trong đó đã giải quyết được vấn đề.
Điều kỳ lạ, là tôi có một số mã hoạt động hoàn hảo (chỉ cần thử nghiệm nó), mặc dù nó không bao giờ gọi enqueue
. Có thể đặt Reference
vào một số Map
bằng cách nào đó kỳ diệu đưa ra tham chiếu?
public class ElementCachedImage {
private static Map<PhantomReference<ElementCachedImage>, File>
refMap = new HashMap<PhantomReference<ElementCachedImage>, File>();
private static ReferenceQueue<ElementCachedImage>
refQue = new ReferenceQueue<ElementCachedImage>();
static {
Thread cleanUpThread = new Thread("Image Temporary Files cleanup") {
@Override
public void run() {
try {
while (true) {
Reference<? extends ElementCachedImage> phanRef =
refQue.remove();
File f = refMap.remove(phanRef);
Calendar c = Calendar.getInstance();
c.setTimeInMillis(f.lastModified());
_log.debug("Deleting unused file: " + f + " created at " + c.getTime());
f.delete();
}
} catch (Throwable t) {
_log.error(t);
}
}
};
cleanUpThread.setDaemon(true);
cleanUpThread.start();
}
ImageWrapper img = null;
private static Logger _log = Logger.getLogger(ElementCachedImage.class);
public boolean copyToFile(File dest) {
try {
FileUtils.copyFile(img.getFile(), dest);
} catch (IOException e) {
_log.error(e);
return false;
}
return true;
}
public ElementCachedImage(BufferedImage bi) {
if (bi == null) throw new NullPointerException();
img = new ImageWrapper(bi);
PhantomReference<ElementCachedImage> pref =
new PhantomReference<ElementCachedImage>(this, refQue);
refMap.put(pref, img.getFile());
new Thread("Save image to file") {
@Override
public void run() {
synchronized(ElementCachedImage.this) {
if (img != null) {
img.saveToFile();
img.getFile().deleteOnExit();
}
}
}
}.start();
}
}
Một số sản lượng lọc:
2013/08/05 22: 35: 01.932 DEBUG Lưu hình ảnh sang file: <> \ AppData \ Local \ Temp \ tmp7..0.PNG
2013-08-05 22: 35: 03,379 DEBUG Xóa tệp không sử dụng: <> \ AppData \ Local \ Temp \ tmp7..0.PNG được tạo tại Mon Aug 05 22:35:02 IDT 2013
Bạn không thực sự enqueue bất cứ điều gì. –
Vì vậy, tôi nên gọi là 'enqueue() '... đã nhận nó, cảm ơn! – Elist
Xem câu trả lời của tôi, dòng cuối cùng. –