如何避免回调中的内存泄漏?

unj*_*nj2 20 java memory-management weak-references callback

有效的Java说:

内存泄漏的第三个常见来源是侦听器和其他回调.如果您实现客户端注册回调但未明确注销回调的API,则除非您采取某些操作,否则它们将累积.确保回调被及时垃圾回收的最佳方法是仅存储对它们的弱引用,例如,通过仅将它们存储为WeakHashMap中的键.

我是Java的初学者.有人可以教我如何在回调中创建弱引用并告诉我它们如何解决内存泄漏问题?谢谢.

Ami*_*ani 12

阅读这篇文章

关键的一点是:

您可以将直接引用视为强引用,无需额外编码即可创建或访问该对象.其余三种类型的引用是java.lang.ref包中的Reference类的子类.软引用由SoftReference类提供,WeakReference类提供弱引用,PhantomReference提供幻像引用.

软引用的作用类似于数据缓存.当系统内存不足时,垃圾收集器可以任意释放其唯一引用为软引用的对象.换句话说,如果没有对对象的强引用,则该对象是发布的候选对象.在抛出OutOfMemoryException之前,垃圾收集器需要释放任何软引用.

弱引用弱于软引用.如果对象的唯一引用是弱引用,则垃圾收集器可以随时回收对象使用的内存.不需要低内存情况.通常,在垃圾收集器的下一次传递中回收对象使用的内存.

幻像引用与清理任务有关.它们在垃圾收集器执行完成过程之前立即提供通知并释放对象.将其视为在对象内执行清理任务的一种方法.

接下来是WeakListModel列表,我不会发布该列表以避免混乱此响应.


Rob*_*ska 8

要通过快速(粗略)示例说明该概念,请考虑以下事项:

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);
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

如果客户端类然后使用此FileMonitorAPI,他们可能会这样做:

public class MyClass {

    File myFile = new File(...);
    FileMonitor monitor = new FileMonitor(myFile);

    public void something() {
        ...
        ChangeHandler myHandler = getChangeHandler();
        monitor.registerChangeHandler(myHandler);
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

如果的作者MyClass,然后忘记调用unregisterChangeHandler()时,它与处理程序完成后,FileMonitorHashSet将永远引用已注册的情况下,使其保留在内存中,直到FileMonitor被破坏,或应用程序退出.

为了防止这种情况,Bloch建议使用弱引用集合而不是使用弱引用集合HashSet,这样如果你的实例MyClass被破坏,引用将从监视器的集合中删除.

您可以使用a 替换HashSetin 并使用处理程序作为键,因为当对象的所有其他引用都消失后,后者将自动从集合中删除处理程序.FileMonitorWeakHashMap