本文翻译自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. access to modified closure 闭包的问题

    ; i < listBoxDevices.Items.Count; i++) { var tempDeviceId = listBoxDevices.Items[i].ToString(); i ...

  2. ERP 推式 拉式 工序拉式 装配拉式 倒冲

    ERP 推式  拉式  工序拉式   装配拉式   倒冲 以上為生产订单(wip)中的原料供应方式,最常用的有Pull和Push. PULL即拉动方式: 拉式生产是生产为主,原材料是由专门的配送人员按 ...

  3. [HDU 1963] Investment

    Investment Time Limit:10000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu   Descrip ...

  4. C#调用C++编写的DLL函数, 以及各种类型的参数传递 z

    1. 如果函数只有传入参数,比如: C/C++ Code Copy Code To Clipboard //C++中的输出函数 int__declspec(dllexport) test(consti ...

  5. 分别应用include指令和include动作标识在一个jsp页面中包含一个文件。

    分别应用include指令和include动作标识在一个jsp页面中包含一个文件. hello.jsp <%@ page language="java" import=&qu ...

  6. Oracle将英文字符集数据转换成中文

    转换背景:老系统数据为英文字符集,需要将老数据(Oracle 8i)转换到oracle 10g(中文字符集)中 思路:先将老数据从8i的数据库中导出,导出的数据库文件为英文字符集,再将10g的数据库改 ...

  7. 关于 Unity 中 ModelImporter.optimizeGameObjects

         ModelImporter.optimizeGameObjects 能够优化骨骼动画,将无用的骨骼合并,效率测试官方给出的数据差距比较大( Unity CJ 干货分享:全新的Unity移动游 ...

  8. 洛谷P1117 棋盘游戏

    洛谷1117 棋盘游戏 题目描述 在一个4*4的棋盘上有8个黑棋和8个白棋,当且仅当两个格子有公共边,这两个格子上的棋是相邻的.移动棋子的规则是交换相邻两个棋子.现在给出一个初始棋盘和一个最终棋盘,要 ...

  9. Hive 0.12 Caused by: MetaException(message:Version information not found in metastore. )解决方法

    配置完成Mysql存储元数据信息,启动后测试show tables报错ERROR exec.DDLTask: org.apache.hadoop.hive.ql.metadata.HiveExcept ...

  10. Sitemap Editors for Dynamics CRM 2013

    I’ve started using a couple of different sitemap editors in my projects for CRM 2013. These tools he ...