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

有效的Java说:

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

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

阅读这篇文章

关键的一点是:

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

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

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

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

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

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

public interface ChangeHandler { public void handleChange(); } public class FileMonitor { private File file; private Set handlers = new HashSet(); 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); } ... } 

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

 public class MyClass { File myFile = new File(...); FileMonitor monitor = new FileMonitor(myFile); public void something() { ... ChangeHandler myHandler = getChangeHandler(); monitor.registerChangeHandler(myHandler); ... } } 

如果MyClass的作者在完成处理程序时忘记调用unregisterChangeHandler() ,则FileMonitorHashSet将永远引用已注册的实例,使其保留在内存中,直到FileMonitor被销毁或应用程序退出。

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

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

在这里您可以找到一个清晰实用的 解释 : Android中的内存泄漏 – 识别,处理和避免