Próbuję zaimplementować mechanizm, który usuwa buforowane pliki, gdy obiekty, które je przechowują, i zdecydował się użyć PhantomReference
s, aby otrzymać powiadomienie o wyrzuceniu śmieci z obiektu. Problem polega na tym, że wciąż doświadczam dziwnego zachowania się ReferenceQueue
. Kiedy zmieniam coś w moim kodzie, nagle nie pobiera już obiektów. Więc starałem się uczynić ten przykład do testowania, i wpadł na ten sam problem:Dlaczego moje obiekty nie umierają?
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();
}
}
}
wyjście jest:
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.
trzeba dodawać, że zmiana czasu sleep
, nazywając gc
wielokrotnie itd nie działa.
UPDATE
Jak sugeruje, zadzwoniłem Reference.enqueue()
mojego odniesienia, który rozwiązał problem.
Najdziwniejsze jest to, że mam trochę kodu, który działa idealnie (po prostu go przetestowałem), chociaż nigdy nie wywołuje enqueue
. Czy możliwe jest, że wstawienie w jakiś magiczny sposób zmaterializowało odniesienie?
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();
}
}
Niektóre filtrowane wyjścia:
2013-08-05 22: 35: 01.932 DEBUG Zapisz obraz do pliku: <> \ AppData \ Local \ Temp \ tmp7..0.PNG
2013-08-05 22: 35: 03,379 DEBUG Usuwanie nieużywanego pliku: <> \ AppData \ Local \ Temp \ tmp7..0.PNG utworzono w Pon Aug 05 22:35:02 IDT 2013
Niczego nie kupisz. –
Więc powinienem zadzwonić 'enqueue()' ... rozumiem, dzięki! – Elist
Zobacz moją odpowiedź, ostatnia linia. –