Effective Java说:
内存泄漏的第三个常见来源是侦听器和其他回调。如果您实现了一个API,其中客户端注册了回调,但没有显式地注销它们,那么这些回调将会累积,除非您采取一些措施。确保回调被及时垃圾回收的最好方法是只存储对它们的弱引用,例如,将它们仅作为键存储在WeakHashMap中。
我是爪哇的初学者。谁能教我如何在回调中创建弱引用,并告诉我它们如何解决内存泄漏问题?谢谢。
发布于 2010-05-19 01:19:47
阅读this文章
关键的收获是:
您可以将直接引用视为强引用,无需额外编码即可创建或访问对象。其余三种类型的引用是在java.lang.ref包中找到的Reference类的子类。软引用由SoftReference类提供,弱引用由WeakReference类提供,幻影引用由PhantomReference提供。
软引用的作用类似于数据缓存。当系统内存不足时,垃圾回收器可以任意释放唯一引用是软引用的对象。换句话说,如果没有对对象的强引用,则该对象是发布的候选对象。在抛出OutOfMemoryException之前,垃圾收集器需要释放任何软引用。
弱引用比软引用弱。如果对对象的唯一引用是弱引用,垃圾回收器可以随时回收对象使用的内存。对于内存不足的情况没有要求。通常,对象使用的内存在垃圾回收器的下一次传递中被回收。
虚拟引用与清理任务相关。它们在垃圾收集器执行终结化过程并释放对象之前立即提供通知。将其视为在对象中执行清理任务的一种方式。
然后是WeakListModel清单,我不会张贴它,以免弄乱这个响应。
发布于 2011-12-12 22:14:04
为了用一个简单的例子来说明这个概念,请考虑以下内容:
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);
}
...
}
如果客户端类随后使用此FileMonitor
应用程序接口,则它们可能会这样做:
public class MyClass {
File myFile = new File(...);
FileMonitor monitor = new FileMonitor(myFile);
public void something() {
...
ChangeHandler myHandler = getChangeHandler();
monitor.registerChangeHandler(myHandler);
...
}
}
如果MyClass
的作者在处理完处理程序后忘记调用unregisterChangeHandler()
,则FileMonitor
的HashSet
将永远引用已注册的实例,导致它一直保留在内存中,直到FileMonitor
被销毁或应用程序退出。
为了防止这种情况,布洛赫建议使用弱引用集合而不是HashSet
,这样如果您的MyClass
实例被销毁,该引用将从监视器的集合中删除。
您可以将FileMonitor
中的HashSet
替换为WeakHashMap
,并使用处理程序作为键,因为当对该对象的所有其他引用都消失时,处理程序将自动从集合中删除。
发布于 2016-07-22 19:43:44
你也可以在这里找到一个清晰的practical 解释:Memory leaks in Android — identify, treat and avoid
https://stackoverflow.com/questions/2859464
复制相似问题