2011-03-23 43 views
4

基础:视图+标记=内存泄漏?

  • 活动 - 每个再现(的onCreate-的onDestroy)orientatin改变
  • 查看由ViewFlipper的两个孩子的:简单的RelativeLayout和ListView
  • 的ListView行具有复杂的布局和相关标签

问题是我有每个方向变化的内存泄漏 - 活动停留在整个视图布局的内存中。活动本身就是一个上下文,所以只要关联的对象会留在内存中。所以现在我试图找出泄漏发生的原因。

查看已有setTag()方法。我用它来存储关于行的一些信息(所以ListView中的每一行(View)都有相关的标签)。

但视图和GC如何与标签一起使用?我的标记对象(持有者)包含对视图的引用,但如果视图删除对其标记的引用,则会轻松收集此引用(带有标记本身)。

有人遇到类似的ListViews问题?

P.S.我想知道GC如何清理布局 - 循环引用,上下文,持有人吨等...

回答

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对象的任何引用,然后依次显示活动引用,进度条等。

一个好的模式我们e有一个“StateHolder”内部类,它包含一个Activity引用,但是我实现了一个setActivityForTasks方法,我只是将NULL传递给它,它依次将所有的Activity引用设置为NULL。然后,当您在方向更改后回到活动状态时,可以拨打setActivityForTasks(this)来重置当前活动。

单外卖只是为NULL了我想你可能有一些非静态内部类的地方在onRetainNonConfigurationInstance

4

相关的任何活动的任何引用,这始终是一个指针保存到其周围的对象实例。例如:

public class A { 

    private class B { 
     // ... 
    } 

    // b stores a reference to the instance of A 
    private B b = new B(); 
} 

如果使用setTag()方法(例如,用于ViewHolder类),绝不会存储在那里的父对象的任何引用。实际上,你应该声明这个类是静态的。

另外,为了避免内存泄漏,如果可能的话,您应该始终将getApplicationContext()的结果传递给需要上下文的方法 - 并且不要引用活动本身。

9

首先,如果您使用View.setTag(int, Object)方法,则可以泄漏对象。使用此方法设置的标签以View作为关键字存储在静态WeakHashMap中。因此,如果您在父视图的标签中存储对子视图的引用,则所有这些视图和它们创建的上下文(父活动)都将被泄漏。发生这种情况的原因是每个子视图都持有对其父项的引用,所以父视图将永远不会被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

纠正我,如果我错了,但我相信标签现在存储在一个SparseArray。 – 2014-06-16 17:31:25

+0

@MM。是的,你是对的。似乎现在在键控标签中存储视图并不是那么危险。谢谢你的评论。 – Michael 2014-06-17 09:31:41

2

姜饼和更低版本的Android,View.setTag (int key, Object tag)泄漏内存。不要使用它。它在ICS中得到了修复。