如何避免回调中的内存泄漏?
有效的Java说:
内存泄漏的第三个常见来源是侦听器和其他回调。如果实现一个 API,其中客户端注册回调但不显式取消注册回调,则除非您采取某些操作,否则回调将累积。确保及时垃圾回收回调的最佳方法是仅存储对它们的弱引用,例如,仅将它们作为键存储在 WeakHashMap 中。
我是Java的初学者。有人可以教我如何在回调中创建弱引用,并告诉我它们如何解决内存泄漏问题吗?谢谢。
有效的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<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);
}
...
}
如果客户端类随后使用此 API,则它们可能会执行以下操作:FileMonitor
public class MyClass {
File myFile = new File(...);
FileMonitor monitor = new FileMonitor(myFile);
public void something() {
...
ChangeHandler myHandler = getChangeHandler();
monitor.registerChangeHandler(myHandler);
...
}
}
如果 then 的作者在处理程序完成操作后忘记调用,则 的 将永远引用已注册的实例,导致它保留在内存中,直到 被销毁或应用程序退出。MyClass
unregisterChangeHandler()
FileMonitor
HashSet
FileMonitor
为了防止这种情况,Bloch 建议使用弱引用集合而不是 ,这样,如果 实例被销毁,引用将从监视器的集合中删除。HashSet
MyClass
您可以将 in 替换为 WeakHashMap
,并使用处理程序作为键,因为当对对象的所有其他引用都消失时,后者将自动从集合中删除处理程序。HashSet
FileMonitor