我需要清理 JNI 调用分配的资源。通过重写方法很容易做到这一点Object.finalize()。由于从 Java 9 开始不推荐使用此方法,因此我尝试使用新java.lang.ref.Cleaner类来实现相同的目标。
ToBeCleaned.cleanUp以下是在实例被垃圾收集之前调用方法的代码:
import java.lang.ref.Cleaner;
import java.lang.ref.WeakReference;
public class ToBeCleaned {
private static Cleaner cleaner = Cleaner.create();
public ToBeCleaned() {
cleaner.register(this, new CleanRunnable(this));
}
void cleanUp () {
// do cleanup
}
static class CleanRunnable implements Runnable {
// It has to be weak reference, otherwise ToBeCleaned instance
// would never be eligible for GC
private WeakReference<ToBeCleaned> toBeCleanedWeakReference;
CleanRunnable(ToBeCleaned toBeCleaned) {
this.toBeCleanedWeakReference = new WeakReference<>(toBeCleaned);
}
@Override
public void run() {
toBeCleanedWeakReference.get().cleanUp();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题:这是正确的方法吗?
Your approach has a flaw. The "cleaning action" must not depend on having access to the instance registered with the Cleaner.
In short, the call to toBeCleanedWeakReference.get() in your code will return null since the ToBeCleaned instance will have been, at least from our perspective, garbage collected by that point.
The correct approach is to somehow reference the resource that needs to be cleaned up without "going through" the ToBeCleaned instance. Typically this means either:
Making the cleaning action and the resource the same object (distinct from the object registered with the Cleaner). The documentation of Cleaner shows an example of this approach.
Passing a reference to the resource, but not the object registered with the Cleaner, to the cleaning action when instantiating it. Here's an example:
public class ToBeCleaned implements AutoCloseable {
// documentation suggests you should preferably have one
// Cleaner instance per library
private static final Cleaner CLEANER = ...;
private final Cleaner.Cleanable cleanable;
private final SomeResource resource;
public ToBeCleaned() {
resource = ...;
cleanable = CLEANER.register(this, new CleaningAction(resource));
}
@Override
public void close() {
cleanable.clean();
}
private static class CleaningAction implements Runnable {
private final SomeResource resource;
CleaningAction(SomeResource resource) {
this.resource = resource;
}
@Override
public void run() {
// clean up 'resource'
}
}
}
Run Code Online (Sandbox Code Playgroud)
Both examples implement AutoCloseable. That gives users of your API the ability to release the resources on-demand rather than waiting for the garbage collector to kick in (which makes the Cleaner more of a "back up").
| 归档时间: |
|
| 查看次数: |
2247 次 |
| 最近记录: |