热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android编程中避免内存泄露的方法总结

这篇文章主要介绍了Android编程中避免内存泄露的方法总结,本文讲解了最可能造成内存泄露的几个点,并总结出如何应对这些内存泄露,需要的朋友可以参考下

Android的应用被限制为最多占用16m的内存,至少在T-Mobile G1上是这样的(当然现在已经有几百兆的内存可以用了——译者注)。它包括电话本身占用的和开发者可以使用的两部分。即使你没有占用全部内存的打算,你也应该尽量少的使用内存,以免别的应用在运行的时候关闭你的应用。Android能在内存中保持的应用越多,用户在切换应用的时候就越快。作为我的一项工作,我仔细研究了Android应用的内存泄露问题,大多数情况下它们是由同一个错误引起的,那就是对一个上下文(Context)保持了长时间的引用。

在Android中,上下文(Context)被用作很多操作中,但是大部分是载入和访问资源。这就是所有的widget都会在它们的构造函数中接受一个上下文(Context)参数。在一个合格的Android应用中,你通常能够用到两种上下文(Context):活动(Activity)和应用(Application)。活动(Activity)通常被传递给需要上下文(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)中保持的所有对象有保持了引用;通常它们包括整个View的层次和它的所有资源。因此,如果你“泄露”了上下文(Context)(这里“泄露”的意思是你保持了一个引用并且组织GC收集它),你将造成大量的内存泄露。如果你不够小心的话,“泄露”一整个活动(Activity)是件非常简单的事情。

当屏幕的方向改变时系统会默认的销毁当前的活动(Activity)并且创建一个新的并且保持了它的状态。这样的结果就是Android会从资源中重新载入应用的UI。现在想象一下,你写了一个应用,有一个非常大的位图,并且你并不想在每次旋转时都重新载入。保留它并且每次旋转不重新加载的最简单的办法就是把它保存在一个静态字段上:

代码如下:

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被设置为drawable的一个回调。在上面的代码片断中,这意味着这个Drawable对TextView有一个引用,同时这个TextView对Activity(Context对象)保持着引用,同时这个Activity对很多对象又有引用(这个多少还要看你的代码了)。

这个例子是造成Context泄露的最简单的一个原因,你可以看一下我们在主屏幕源码(查看unbindDrawables()方法)中是通过在Activity销毁时设置保存过的Drawable的回调为空来解决这个问题的。更为有趣的是,你可以创建一个context泄露的链,当然这非常的糟糕。它们可以让你飞快的用光所有的内存。

有两种简单的方法可以避免与context相关的内存泄露。最明显的一个就是避免在context的自身的范围外使用它。上面的例子展示了在类内部的一个静态的引用和它们对外部类的间接引用是非常危险的。第二个解决方案就是使用Application Context。这个context会伴随你的应用而存在,并且不依赖Activity的的生命周期。如果你计划保持一个需要context的长生命周期的对象,请记得考虑Application对象。你可以非常方便的通过调用Context.getApplicationContext() 或者 Activity.getApplication()获取它。

总之,为了避免涉及到context的内存泄露,请记住如下几点:

1.不要对一个Activity Context保持长生命周期的引用(一个对Activity的引用应该与Activity自身的生命周期相同)
2.尝试使用应用上下文(context-application)代替活动上下文(context-activity)
3.如果你不能控制它们的生命周期,在活动(Activity)中避免使用不是静态的内部类,使用静态类并且使用弱引用到活动(Activity)的内部。对于这个问题的解决方法是使用静态的内部类与一个弱引用(WeakReference)的外部类。就像ViewRoot和它的W内部类那么实现的。
4.垃圾回收器对于内存泄露来说并不是百分百保险的。


推荐阅读
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 【Windows】实现微信双开或多开的方法及步骤详解
    本文介绍了在Windows系统下实现微信双开或多开的方法,通过安装微信电脑版、复制微信程序启动路径、修改文本文件为bat文件等步骤,实现同时登录两个或多个微信的效果。相比于使用虚拟机的方法,本方法更简单易行,适用于任何电脑,并且不会消耗过多系统资源。详细步骤和原理解释请参考本文内容。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 本文讲述了作者通过点火测试男友的性格和承受能力,以考验婚姻问题。作者故意不安慰男友并再次点火,观察他的反应。这个行为是善意的玩人,旨在了解男友的性格和避免婚姻问题。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
轩轩20110804
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有