源码:jna5.15.0
CleanerRef继承了虚引用PhantomReference,当Memory对象被GC的时候,把它的虚引用对象(PhantomReference)存入referenceQueue队列中,CleanerThread会一直轮询检查队列中是否有虚引用对象,如果有则触发clean方法。
private static class CleanerRef extends PhantomReference<Object> implements Cleanable {
private final Cleaner cleaner;
private final Runnable cleanupTask;
private CleanerRef previous;
private CleanerRef next;
public CleanerRef(Cleaner cleaner, Object referent, ReferenceQueue<? super Object> q, Runnable cleanupTask) {
super(referent, q);
this.cleaner = cleaner;
this.cleanupTask = cleanupTask;
}
@Override
public void clean() {
// 清理Native内存
if(cleaner.remove(this)) {
cleanupTask.run();
}
}
CleanerRef getPrevious() {
return previous;
}
void setPrevious(CleanerRef previous) {
this.previous = previous;
}
CleanerRef getNext() {
return next;
}
void setNext(CleanerRef next) {
this.next = next;
}
}
private class CleanerThread extends Thread {
private static final long CLEANER_LINGER_TIME = 30000;
public CleanerThread() {
super("JNA Cleaner");
setDaemon(true);
}
@Override
public void run() {
while (true) {
try {
Reference<? extends Object> ref = referenceQueue.remove(CLEANER_LINGER_TIME);
if (ref instanceof CleanerRef) {
// 队列中有数据,代表对象被GC,触发定义的clean方法
((CleanerRef) ref).clean();
} else if (ref == null) {
synchronized (referenceQueue) {
Logger logger = Logger.getLogger(Cleaner.class.getName());
if (firstCleanable == null) {
cleanerThread = null;
logger.log(Level.FINE, "Shutting down CleanerThread");
break;
} else if (logger.isLoggable(Level.FINER)) {
StringBuilder registeredCleaners = new StringBuilder();
for(CleanerRef cleanerRef = firstCleanable; cleanerRef != null; cleanerRef = cleanerRef.next) {
if(registeredCleaners.length() != 0) {
registeredCleaners.append(", ");
}
registeredCleaners.append(cleanerRef.cleanupTask.toString());
}
logger.log(Level.FINER, "Registered Cleaners: {0}", registeredCleaners.toString());
}
}
}
} catch (InterruptedException ex) {
// Can be raised on shutdown. If anyone else messes with
// our reference queue, well, there is no way to separate
// the two cases.
// https://groups.google.com/g/jna-users/c/j0fw96PlOpM/m/vbwNIb2pBQAJ
break;
} catch (Exception ex) {
Logger.getLogger(Cleaner.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}