问题
Effective Java says:
A third common source of memory leaks is listeners and other callbacks. If you implement an API where clients register callbacks but don’t deregister them explicitly, they will accumulate unless you take some action. The best way to ensure that callbacks are garbage collected promptly is to store only weak references to them, for instance, by storing them only as keys in a WeakHashMap.
I am a beginner in Java. Could somebody teach me how to create weak references in callbacks and tell me how they solve the memory leak problems? Thanks.
回答1:
Read this article
The key take aways are :
You can think of direct references as strong references that require no extra coding to create or access the object. The remaining three types of references are subclasses of the Reference class found in the java.lang.ref package. Soft references are provided by the SoftReference class, weak references by the WeakReference class, and phantom references by PhantomReference.
Soft references act like a data cache. When system memory is low, the garbage collector can arbitrarily free an object whose only reference is a soft reference. In other words, if there are no strong references to an object, that object is a candidate for release. The garbage collector is required to release any soft references before throwing an OutOfMemoryException.
Weak references are weaker than soft references. If the only references to an object are weak references, the garbage collector can reclaim the memory used by an object at any time. There is no requirement for a low memory situation. Typically, memory used by the object is reclaimed in the next pass of the garbage collector.
Phantom references relate to cleanup tasks. They offer a notification immediately before the garbage collector performs the finalization process and frees an object. Consider it a way to do cleanup tasks within an object.
followed by the WeakListModel listing which I won't post to avoid cluttering this response.
回答2:
To illustrate the concept with a quick (crude) example, consider the following:
public interface ChangeHandler {
public void handleChange();
}
public class FileMonitor {
private File file;
private Set<ChangeHandler> handlers = new HashSet<ChangeHandler>();
public FileMonitor(File file) {
this.file = file;
}
public void registerChangeHandler(ChangeHandler handler) {
this.handlers.add(handler);
}
public void unregisterChangeHandler(ChangeHandler handler) {
this.handlers.remove(handler);
}
...
}
If a client class then uses this FileMonitor
API, they might do this:
public class MyClass {
File myFile = new File(...);
FileMonitor monitor = new FileMonitor(myFile);
public void something() {
...
ChangeHandler myHandler = getChangeHandler();
monitor.registerChangeHandler(myHandler);
...
}
}
If the author of the MyClass
then forgets to call unregisterChangeHandler()
when it's done with the handler, the FileMonitor
's HashSet
will forever reference the instance that was registered, causing it to remain in memory until the FileMonitor
is destroyed or the application quits.
To prevent this, Bloch is suggesting using a weak-referencing collection instead of the HashSet
, so that if your instance of MyClass
is destroyed, the reference will be removed from the monitor's collection.
You might replace the HashSet
in FileMonitor
with a WeakHashMap and use the handlers as the keys, since the latter will automatically remove the handler from the collection when all other references to the object are gone.
回答3:
Here you may find a clear and practical explanation as well: Memory leaks in Android — identify, treat and avoid
来源:https://stackoverflow.com/questions/2859464/how-to-avoid-memory-leaks-in-callback