避免Android上的内存泄漏

我刚刚阅读了罗曼·盖伊(Romain Guy)关于如何避免Android内存泄漏的博文。

在这篇文章中,他给出了这个例子:

private static Drawable sBackground; @Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label); } 

罗曼说:

这个例子是泄漏Context的最简单的例子之一。

我的问题是,你如何正确地修改它?

像这样?

 TextView label = new TextView(Context.getApplicationContext()); 

我testing了两种方法,结果是一样的。 我找不到差异。 我认为this比Application上下文更正确。 因为this是对Activity的引用,也就是说, TextView属于该Activity

有人能给我一个解释吗?

Solutions Collecting From Web of "避免Android上的内存泄漏"

该代码的实际问题不是创build可绘制的上下文,而是私有的静态Drawable sBackground; 静态Drawable是以Activity作为上下文创build的,所以在这种情况下,有一个引用Activity的Drawable的静态引用,这就是为什么会有泄漏。 只要有这个参考,活动就会一直记在脑后,漏掉了所有的观点。

因此,应该使用应用程序上下文来创buildDrawable,而不是TextView。 用“this”创buildTextView是完全正确的。

编辑:实际上,这可能没有太大的区别,问题是,一旦drawable绑定到一个视图,就有一个引用该视图的引用该活动的引用。 所以当你退出活动时你需要“解开”drawable。

我不确定Romain是否阅读过之后更新了他的博客文章,但是他很清楚如何避免漏洞,甚至指出你在Android操作系统中的一个例子。 请注意,我通过archive.org在Romain的博客条目中修复了损坏的链接。

这个例子是泄漏上下文最简单的例子之一,你可以看到我们是如何在主屏幕的源代码中解决它的 (查找unbindDrawables()方法),通过设置存储的drawables的callback为null当活动被破坏。 有趣的是,有些情况下,你可以创build一个泄漏的上下文链,而且是不好的。 它们让你快速地耗尽记忆。

有两种简单的方法可以避免上下文相关的内存泄漏。 最明显的就是避免脱离自己范围之外的背景。 上面的例子显示了一个静态引用的情况,但是内部类和它们对外部类的隐式引用可能同样危险。 第二个解决scheme是使用应用程序上下文。 只要您的应用程序处于活动状态,并且不依赖于活动的生命周期,此上下文就会生效。 如果您打算保留需要上下文的长寿命对象,请记住应用程序对象。 你可以通过调用Context.getApplicationContext()或者Activity.getApplication()来获得它。

总之,为了避免上下文相关的内存泄漏,请记住以下内容:

  • 不要长期引用上下文活动(对活动的引用应该与活动本身具有相同的生命周期)
  • 尝试使用上下文应用程序而不是上下文活动
  • 避免活动中的非静态内部类,如果您不控制其生命周期,请使用静态内部类并对其中的活动进行弱引用。 这个问题的解决scheme是使用一个带有WeakReference的静态内部类到外部类,就像ViewRoot和它的W内部类一样
  • 垃圾收集器不是防止内存泄漏的保险

内存泄漏在那个代码主要发生在你旋转你的屏幕时(也就是改变方向状态),所以你的活动被破坏并重新创build新的方向。 关于内存泄漏有很多解释。

您可以在这里查看一下关于内存pipe理的Google I / O 2011video。 在video中,您还可以使用内存pipe理工具(如Memory Analyzer) 在这里下载。

我不知道在你的应用程序中是否有任何问题,但是我已经创build了一个解决scheme,用标准的android类来修复所有的android内存泄漏问题: http : //code.google.com/p/安卓/问题/细节?ID = 8488#C51

 public abstract class BetterActivity extends Activity { @Override protected void onResume() { System.gc(); super.onResume(); } @Override protected void onPause() { super.onPause(); System.gc(); } @Override public void setContentView(int layoutResID) { ViewGroup mainView = (ViewGroup) LayoutInflater.from(this).inflate(layoutResID, null); setContentView(mainView); } @Override public void setContentView(View view) { super.setContentView(view); m_contentView = (ViewGroup)view; } @Override public void setContentView(View view, LayoutParams params) { super.setContentView(view, params); m_contentView = (ViewGroup)view; } @Override protected void onDestroy() { super.onDestroy(); // Fixes android memory issue 8488 : // http://code.google.com/p/android/issues/detail?id=8488 nullViewDrawablesRecursive(m_contentView); m_contentView = null; System.gc(); } private void nullViewDrawablesRecursive(View view) { if(view != null) { try { ViewGroup viewGroup = (ViewGroup)view; int childCount = viewGroup.getChildCount(); for(int index = 0; index < childCount; index++) { View child = viewGroup.getChildAt(index); nullViewDrawablesRecursive(child); } } catch(Exception e) { } nullViewDrawable(view); } } private void nullViewDrawable(View view) { try { view.setBackgroundDrawable(null); } catch(Exception e) { } try { ImageView imageView = (ImageView)view; imageView.setImageDrawable(null); imageView.setBackgroundDrawable(null); } catch(Exception e) { } } // The top level content view. private ViewGroup m_contentView = null; }