How to avoid memory leaks in callback?

拥有回忆 提交于 2019-12-18 11:50:03

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!