本文翻译自Avoiding memory leak——Post by Romain Guy

著作权归原作者所有。转载请注明出处,由JohnTsai翻译


Android应用被分配的堆的大小限制为16MB。这对于手机来说已经很多了,但对于一些开发者想获得的来说仍旧不够。即使你没有计划使用所有的这些内存。你应该尽可能的少用以避免其他应用在运行时因为内存不足而被杀掉。Android内存中保存的应用越多,用户在应用间切换得越快。作为我工作的一部分,我在Android应用中遇到过得内存泄露问题,它们大多数时候是因为同一个错误:对Context维持了一个长时间的引用


在Android中,Context可用于很多操作,但主要是用于加载和访问资源。这就是为什么所有的widget都要在它们的构造方法中接收Context参数。在一个常规的Android应用中,通常有两种Context:ActivityApplication

一般开发者将前者传递给需要Context的类和方法:

@Override
protected void onCreate(Bundle state) {
super.onCreate(state); TextView label = new TextView(this);
label.setText("Leaks are bad"); setContentView(label);
}

 

这意味着View有一整个Activity的引用。因此可访问到Activity持有的任何东西。因此,如果你泄露了Context(泄露(leak)意味着你维持了一个指向它的引用导致GC不能回收它),你就泄露了很多内存。如果你不小心的话,非常容易就会泄露整个Activity。

当屏幕的方向改变时,系统默认会销毁当前的Activity并保存它的状态,然后创建一个新的Activity。在这个过程中,Android会从资源中重新加载应用的UI。现在假设你写了一个有大bitmap的应用,你不想每次旋转时都加载bitmap。维持这个实例、不需要每次重新加载的最简单的办法就是将它维持在一个静态域中。

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);
}

这个代码是非常便捷但是也非常错误。它泄露了第一次因屏幕方向改变而创建的Activity。当一个Drawable对象依附到一个View对象上时,View对象被作为一个callback设置到drawable对象上了。在上面的代码片段中,这就意味着drawable有一个TextView的引用,而TextView有activity的引用(Context),activity有很多东西的原因(取决于你的代码)

这个例子是Context泄露的最简单的例子,你可以看看我们在Home screen的源码中是如何处理这种问题的(看unbindDrawables()方法),通过在activity销毁时,将存储的drawable的callback为null。有趣的是,有多种情况能导致我们创建泄露的Context,这样很糟糕。它们使得我们很快就耗尽内存。

有两种简单的方法可避免Context相关的内存泄露。

  • 最明显的方法是避免在Context的作用域之外使用它。上面那个例子展示了静态引用或是内部类对外部类的隐式引用都是同样危险的。
  • 第二种方法就是使用Application Context。这个Context会一直存活只要你的应用是活着的,并且不依赖于Activity的生命周期。如果你打算维持一个长时间存在的并且需要Context的对象时,记住使用应用的Context。获取方法:Context.getApplicationContext()或Activity.getApplication()

概况来说,为了避免Context相关的内存泄露,记住下面几点:

  • 不要维持一个长时间存在对Activity的Context的引用(Activity的引用和Activity有着一样的生命周期)
  • 使用Application的Context而不是Activity的Context
  • 避免在Activity中使用非静态内部类,如果你不想控制他们的生命周期。使用静态内部类,并在它的内部创建一个对Activity的弱引用。

下面的例子由译者补充

使用非静态内部类,Android Studio报可能内存泄露的警告:

//解决方法
//使用静态内部类,并在其中创建对Activity的弱引用
 private static class MyHandler extends Handler{

        //对Activity的弱引用
private final WeakReference<HandlerActivity> mActivity; public MyHandler(HandlerActivity activity){
mActivity = new WeakReference<HandlerActivity>(activity);
} @Override
public void handleMessage(Message msg) {
HandlerActivity activity = mActivity.get();
if(activity==null){
super.handleMessage(msg);
return;
}
switch (msg.what) {
case DOWNLOAD_FAILED:
Toast.makeText(activity, "下载失败", Toast.LENGTH_SHORT).show();
break;
case DOWNLOAD_SUCCESS:
Toast.makeText(activity, "下载成功", Toast.LENGTH_SHORT).show();
Bitmap bitmap = (Bitmap) msg.obj;
activity.imageView.setVisibility(View.VISIBLE);
activity.imageView.setImageBitmap(bitmap);
break;
default:
super.handleMessage(msg);
break;
}
}
} private final MyHandler mHandler = new MyHandler(this);
  • 垃圾回收器不是针对内存泄露的保险。

Android开发——避免内存泄露的更多相关文章

  1. Android DDMS检测内存泄露

    Android DDMS检测内存泄露 DDMS是Android开发包中自带工具,可以测试app性能,用于发现内存问题. 1.环境搭建 参考之前发的Android测试环境搭建相关文章,这里不再复述: 2 ...

  2. 查找并修复Android中的内存泄露—OutOfMemoryError

    [编者按]本文作者为来自南非约翰内斯堡的女程序员 Rebecca Franks,Rebecca 热衷于安卓开发,拥有4年安卓应用开发经验.有点完美主义者,喜爱美食. 本文系国内ITOM管理平台 One ...

  3. LeakCanary Android 和 Java 内存泄露检测

    说起内存泄漏还是挺让人头疼的,而且不是每个手机都会发生的情况,往往又不易察觉,那么今天我们就来介绍下LeakCanary这个工具 githup:https://github.com/square/le ...

  4. Android开发中内存和UI优化

    1.内存||效率 GC这东西对于开发人员用起来比较爽,但对于技术总监或产品总监来说,他们并不在乎,在乎的是用户运行App的流畅度,待你开发完了,笑眯眯的走过来,让你测试N个适配器,烦都烦死你. 说到这 ...

  5. 如何快速排查解决Android中的内存泄露问题

    概述 内存泄露是Android开发中比较常见的问题,一旦发生会导致大量内存空间得不到释放,可用内存急剧减少,导致运行卡顿,部分功能不可用甚至引发应用crash.对于复杂度比较高.多人协同开发的项目来讲 ...

  6. 使用新版Android Studio检测内存泄露和性能

    内存泄露,是Android开发者最头疼的事.可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴.  怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的 ...

  7. Android Handler的内存泄露问题+解决方案

    谈谈handler的内存泄露问题 再来看看我们的新建Handler的代码: private Handler mHandler = new Handler() { @Override public vo ...

  8. 如何用MAT分析Android程序的内存泄露

    本文结合<Android开发艺术探索>书籍中的内存分析例子来讲解如何利用MAT工具来查找内存泄漏(以AndroidStudio开发工具为例). 1.下载MAT(Eclipse Memory ...

  9. Android Studio检测内存泄露和性能

    韩梦飞沙 yue31313 韩亚飞 han_meng_fei_sha 313134555@qq.com 首先需要明白一个概念, 内存泄露就是指,本应该回收的内存,还驻留在内存中. 一般情况下,高密度的 ...

随机推荐

  1. easyui 中的treegrid添加checkbox

    <script type="text/javascript"> function show(checkid){ var s = '#check_'+checkid; / ...

  2. 如何在 Windows 7 安裝 SharePoint Server 2010

    转:http://support.microsoft.com/kb/2683572/zh-tw 關於作者: 本文由微軟最有價值專家 MVP 歐志信 提供.微軟十分感謝 MVP 主動地將他們的經驗與上百 ...

  3. 【转】Compile FFmpeg on CentOS 6.x

    This guide is based on a minimal CentOS installation and will install FFmpeg with several external e ...

  4. [新]最近用unity5弄的一些渲染

    Unity Separable Bokeh Depth-of-Field Hexagonal Blur Unity3d Realtime Dynamic Clouds Rendering hemisp ...

  5. 【转】傅里叶变换 拉普拉斯变 z变换 DFT DCT意义

    傅里叶变换在物理学.数论.组合数学.信号处理.概率论.统计学.密码学.声学.光学.海洋学.结构动力学等领域都有着广泛的应用(例如在信号处理中,傅里叶变换的典型用途是将信号分解成幅值分量和频率分量). ...

  6. Linux中的模式转换

    模式转换: 编辑-->输入: i: 在当前光标所在字符的前面,转为输入模式: a: 在当前光标所在字符的后面,转为输入模式: o: 在当前光标所在行的下方,新建一行,并转为输入模式: I:在当前 ...

  7. spoj 1812 LCS2(SAM+DP)

    [题目链接] http://www.spoj.com/problems/LCS2/en/ [题意] 求若干个串的最长公共子串. [思路] SAM+DP 先拿个串建个SAM,然后用后面的串匹配,每次将所 ...

  8. awk学习

    首先分享一个哥们的文章:http://coolshell.cn/articles/9070.html

  9. 【解决】HDFS HA无法自动切换问题

    [解决]HDFS HA无法自动切换问题 原因: 最早设置为root互相登录,可是zkfc服务是hdfs账号运行的,没有权限访问到root的id_rsa文件.更改为hdfs账号免密钥登录恢复正常.   ...

  10. The iOS Design Cheat Sheet 界面设计速参

    http://ivomynttinen.com/blog/the-ios-7-design-cheat-sheet/ With the release of iOS 7, app designers ...