本文翻译自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. BZOJ_1615_[Usaco2008_Mar]_The Loathesome_Hay Baler_麻烦的干草打包机_(模拟+宽搜/深搜)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1615 一个主动轮带着一些轮子转,轮子带着轮子转,轮子带着轮子转...一个非主动轮只会被一个轮子 ...

  2. Codevs_1166_[NOIP2007]_矩阵取数游戏_(动态规划+高精度)

    描述 http://codevs.cn/problem/1166/ 分析 #include <iostream> #include <cstring> #include < ...

  3. PHP libxml RSHUTDOWN安全限制绕过漏洞(CVE-2012-1171)

    漏洞版本: PHP PHP 5.5.x 漏洞描述: BUGTRAQ ID: 65673 CVE(CAN) ID: CVE-2012-1171 PHP是一种HTML内嵌式的语言. PHP 5.x版本内的 ...

  4. js模拟Map对象,实现key---value

    js模拟Map对象,实现key---value 根据java中map的属性,实现key----value保存 function Map() { var struct = function (key, ...

  5. Jquery 输入金额格式限制 插件

    (function($) { $.fn.extend({ money_mode: function(options) { var defaults = { decimal_length: 2,//小数 ...

  6. SQL中取当前记录的ID----->SCOPE_IDENTITY()

    SQL Server 2000中,有三个比较类似的功能:他们分别是:SCOPE_IDENTITY.IDENT_CURRENT 和 @@IDENTITY,它们都返回插入到 IDENTITY 列中的值.I ...

  7. YUV格式总结

    1. YUV是被欧洲电视系统所采用的一种颜色编码方法(属于PAL),是PAL和SECAM模拟彩色电视制式采用的颜色空间.在现代彩色电视系统中,通常采用三管彩色摄影机或彩色CCD摄影机进行取像,然后把取 ...

  8. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程05:技能读表》

    5.技能读表 技能读表概述: 技能读表,作为实现技能系统更为快捷的一种方式,被广泛应用到游戏开发中.技能配表,作为桥梁连接着游戏策划者和开发者在技能实现上的关系.在游戏技能开发中,开发者只需要根据策划 ...

  9. 【Java基础】用LinkedList实现一个简单栈的功能

    栈的基本功能 栈的最基本功能是保障后进先出,然后在此基础上可以对在栈中的对象进行弹入弹出,此外,在弹出时,如果栈为空,则会报错,所以还需要提供获取当前栈大小的方法. 构造存储对象Student /** ...

  10. HW5.13

    public class Solution { public static void main(String[] args) { System.out.printf("%s\t%s\n&qu ...