基础:
问题是我在每个方向更改时都有内存泄漏 - 活动在整个视图布局中保留在内存中。活动本身就是一个上下文,所以只要关联对象就会保留在内存中。所以现在我想找到泄密事件发生的原因。
View具有 setTag()方法。我用它来存储一些关于行的信息(因此ListView中的每一行(View)都有关联的标签)。
但是视图和GC如何处理标签?我的标记对象(持有者)包含对视图的引用,但如果视图删除了对它的标记的引用,则可以很容易地收集引用(带有标记本身)。
有人遇到类似ListViews的问题吗?
P.S。我想知道GC如何清理布局 - 循环引用,上下文,持有者等等......
答案 0 :(得分:9)
首先,如果使用View.setTag(int, Object)
方法,可以泄漏对象。使用此方法设置的标记存储在静态WeakHashMap
中,其中View
为关键字。因此,如果您在父视图的标记中存储对子视图的引用,那么所有这些视图以及它们(父活动)创建的上下文都将被泄露。这是因为每个子视图都包含对其父视图的引用,因此GC将永远不会收集父视图。
有一种简单的方法可以模拟这种行为:
public static class MainActivity extends ListActivity {
private final WeakHashMap<Parent, Parent.Child> mMap =
new WeakHashMap<Parent, Parent.Child>();
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// If parents were collected OOM error wouldn't be thrown.
// But they aren't collected so we get OOM here.
for (int i = 0; i < 10; ++i) {
Parent parent = new Parent();
mMap.put( parent, parent.mChild );
}
}
}
public static class Parent {
public final Child mChild = new Child();
public class Child {
private final byte[] mJunk = new byte[10*1024*1024];
}
}
其次,似乎ListView
类导致内存泄漏。这意味着列表视图,其所有可回收的子项及其父活动都被泄露。以下是有关此错误的一些信息:
答案 1 :(得分:4)
我认为你可能在某处有一些非静态的内部类,它总是保存指向它们周围对象实例的指针。例如:
public class A {
private class B {
// ...
}
// b stores a reference to the instance of A
private B b = new B();
}
如果使用setTag()方法(例如,对于ViewHolder类),则永远不要存储对父对象的任何引用。实际上,您应该将此类声明为静态。
另外,为了避免内存泄漏,如果可能的话,你应该总是将getApplicationContext()的结果传递给需要Context的方法 - 而不是对Activity本身的引用。
答案 2 :(得分:3)
很容易泄漏对方向更改的活动的引用。有一些关于此的博客文章 - 我认为需要阅读:
http://ttlnews.blogspot.com/2010/01/attacking-memory-problems-on-android.html
http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
http://code.google.com/p/android/issues/detail?id=2391
在onRetainNonConfigurationInstance
方法的一个超级简介中,您只需要注意忽略对View对象的任何引用,然后依次调用Activity引用,进度条等。
我使用的一个好模式是有一个“StateHolder”内部类,它确实包含一个Activity引用,但我实现了一个setActivityForTasks
方法,我只是将NULL传递给它,它又将所有Activity引用设置为NULL 。然后,当您在更改方向后返回活动时,您只需拨打setActivityForTasks(this)
即可重置当前活动。
单一外卖只是对onRetainNonConfigurationInstance
答案 3 :(得分:2)
在Gingerbread和Android的较低版本中,View.setTag (int key, Object tag)
泄漏内存。不要使用它。它已在ICS中修复。