@override
protected void oncreate(bundle state) {
super.oncreate(state);
textview label = new textview(this);
label.settext("leaks are bad");
setcontentview(label);
}
这就意味着那个view有一个对整个活动(activity)的引用并且对这个活动(activity)中保持的所有对象有保持了引用;通常它们包括整个view的层次和它的所有资源。因此,如果你“泄露”了上下文(context)(这里“泄露”的意思是你保持了一个引用并且组织gc收集它),你将造成大量的内存泄露。如果你不够小心的话,“泄露”一整个活动(activity)是件非常简单的事情。
当屏幕的方向改变时系统会默认的销毁当前的活动(activity)并且创建一个新的并且保持了它的状态。这样的结果就是android会从资源中重新载入应用的ui。现在想象一下,你写了一个应用,有一个非常大的位图,并且你并不想在每次旋转时都重新载入。保留它并且每次旋转不重新加载的最简单的办法就是把它保存在一个静态字段上:
private static drawable sbackground;
if (sbackground == null) {
sbackground = getdrawable(r.drawable.large_bitmap);
}
label.setbackgrounddrawable(sbackground);
这段代码非常快,同时也错的够离谱。它泄露了当第一次屏幕角度改变时创建的第一个活动(activity)。当一个drawable被附加到一个view,这个view被设置为drawable的一个回调。在上面的代码片断中,这意味着这个drawable对textview有一个引用,同时这个textview对activity(context对象)保持着引用,同时这个activity对很多对象又有引用(这个多少还要看你的代码了)。
有两种简单的方法可以避免与context相关的内存泄露。最明显的一个就是避免在context的自身的范围外使用它。上面的例子展示了在类内部的一个静态的引用和它们对外部类的间接引用是非常危险的。第二个解决方案就是使用application context。这个context会伴随你的应用而存在,并且不依赖activity的的生命周期。如果你计划保持一个需要context的长生命周期的对象,请记得考虑application对象。你可以非常方便的通过调用context.getapplicationcontext()
或者 activity.getapplication()获取它。
总之,为了避免涉及到context的内存泄露,请记住如下几点:
不要对一个activity context保持长生命周期的引用(一个对activity的引用应该与activity自身的生命周期相同)
尝试使用应用上下文(context-application)代替活动上下文(context-activity)
如果你不能控制它们的生命周期,在活动(activity)中避免使用不是静态的内部类,使用静态类并且使用弱引用到活动(activity)的内部。对于这个问题的解决方法是使用静态的内部类与一个弱引用(weakreference)的外部类。就像viewroot和它的w内部类那么实现的。
垃圾回收器对于内存泄露来说并不是百分百保险的。