常见的八种导致 APP 内存泄漏的问题(上)

百度搜索:小强测试品牌

QQ群:138269539

像 Java 这样具有垃圾回收功能的语言的好处之一,就是程序员无需手动管理内存分配。这减少了段错误(segmentation fault)导致的闪退,也减少了内存泄漏导致的堆空间膨胀,让编写的代码更加安全。然而,Java 中依然有可能发生内存泄漏。所以你的安卓 APP 依然有可能浪费了大量的内存,甚至由于内存耗尽(OOM)导致闪退。

传统的内存泄漏是由忘记释放分配的内存导致的,而逻辑上的内存泄漏则是由于忘记在对象不再被使用的时候释放对其的引用导致的。如果一个对象仍然存在强引用,垃圾回收器就无法对其进行垃圾回收。在安卓平台,泄漏 Context 对象问题尤其严重。这是因为像Activity 这样的 Context 对象会引用大量很占用内存的对象,例如 View 层级,以及其他的资源。如果 Context 对象发生了内存泄漏,那它引用的所有对象都被泄漏了。安卓设备大多内存有限,如果发生了大量这样的内存泄漏,那内存将很快耗尽。

如果一个对象的合理生命周期没有清晰的定义,那判断逻辑上的内存泄漏将是一个见仁见智的问题。幸运的是,activity 有清晰的生命周期定义,使得我们可以很明确地判断 activity 对象是否被内存泄漏。onDestroy() 函 数将在 activity 被销毁时调用,无论是程序员主动销毁 activity,还是系统为了回收内存而将其销毁。如果 onDestroy 执行完毕之后,activity 对象仍被 heap root 强引用,那垃圾回收器就无法将其回收。所以我们可以把生命周期结束之后仍被引用的 activity 定义为被泄漏的 activity。

Activity 是非常重量级的对象,所以我们应该极力避免妨碍系统对其进行回收。然而有多种方式会让我们无意间就泄露了 activity 对象。

我们把可能导致 activity 泄漏的情况分为两类,一类是使用了进程全局(process-global)的静态变量,无论 APP 处于什么状态,都会一直存在,它们持有了对 activity 的强引用进而导致内存泄漏,另一类是生命周期长于 activity 的线程,它们忘记释放对 activity 的强引用进而导致内存泄漏。下面我们就来详细分析一下这些可能导致 activity 泄漏的情况。

静态 Activity



泄漏 activity 最简单的方法就是在 activity 类中定义一个 static 变量,并且将其指向一个运行中的 activity 实例。 如果在 activity 的生命

周期结束之前,没有清除这个引用,那它就会泄漏了。这是因为 activity(例如 MainActivity) 的类对象是静态的,一旦加载,就会在

APP 运行时一直常驻内存,因此如果类对象不卸载,其静态成员就不会被垃圾回收。

静态 View



另一种类似的情况是对经常启动的 activity 实现一个单例模式,让其常驻内存可以使它能够快速恢复状态。然而,就像前文所述,不遵循系统定义的 activity 生命周期是非常危险的,也是没必要的,所以我们应该极力避免。

但是如果我们有一个创建起来非常耗时的 View,在同一个 activity 不同的生命周期中都保持不变呢?所以让我们为它实现一个单例模式,就像这段代码。现在一旦 activity 被销毁,那我们就应该释放大部分的内存了

内 存泄漏了!因为一旦 view 被加入到界面中,它就会持有 context 的强引用,也就是我们的 activity。由于我们通过一个静态成员引用了这个 view,所以我们也就引用了 activity,因此 activity 就发生了泄漏。所以一定不要把加载的 view 赋值给静态变量,如果你真的需要,那一定要确保在 activity 销毁之前将其从 view 层级中移除。

内部类



现在让我们在 activity 内部定义一个类,也就是内部类。这样做的原因有很多,比如增加封装性和可读性。如果我们创建了一个内部类的对象,并且通过静态变量持有了 activity 的引用,那也会发生 activity 泄漏。

不幸的是,内部类能够引用外部类的成员这一优势,就是通过持有外部类的引用来实现的,而这正是 activity 泄漏的原因。

匿名类



类似的,匿名类同样会持有定义它们的对象的引用。因此如果在 activity 内定义了一个匿名的 AsyncTask 对象,就有可能发生内存泄漏了。如果 activity 被销毁之后 AsyncTask 仍然在执行,那就会组织垃圾回收器回收 activity 对象,进而导致内存泄漏,直到执行结束才能回收 activity。

时间: 2024-07-29 01:46:34

常见的八种导致 APP 内存泄漏的问题(上)的相关文章

常见的八种导致 APP 内存泄漏的问题(下)

百度搜索:小强测试品牌 QQ群:138269539 Handlers 同 样的,定义一个匿名的 Runnable 对象并将其提交到 Handler 上也可能导致 activity 泄漏.Runnable 对象间接地引用了定义它的activity 对象,而它会被提交到 Handler 的 MessageQueue 中,如果它在 activity 销毁时还没有被处理,那就会导致 activity 泄漏了. Threads 同样的,使用 Thread 和 TimerTask 也可能导致 activit

使用HandyJSON导致的内存泄漏问题相关解决方法

在移动开发中,与服务器打交道是不可避免的,从服务器拿到的接口数据最终都会被我们解析成模型,现在比较常见的数据传输格式是json格式,对json格式的解析可以使用原生的解析方式,也可以使用第三方的,我们的项目中使用的是阿里开源的一个swift编写的解析框架--HandyJSON. 在使用过程中,使用instruments的Leak Checks工具对内存泄漏进行检测时发现了这个框架导致了不少的内存泄漏,如图1-1: 这张图是在APP进入首页并将数据加载完毕时截取的,可以看到,HandyJSON一共

View的post方法导致的内存泄漏分析

简述: 写这篇文章的缘由是最近项目中查内存泄漏时,发现最终原因是由于异步线程调用View的的post方法导致的. 为何我会使用异步线程调用View的post方法,是因为项目中需要用到很多复杂的自定义布局,需要提前解析进入内存,防止在主线程解析导致卡顿,具体的实现方法是在Application启动的时候,使用异步线程解析这些布局,等需要使用的时候直接从内存中拿来用. 造成内存泄漏的原因,需要先分析View的post方法执行流程,也就是文章前半部分的内容 文章内容: View#post方法作用以及实

static关键字所导致的内存泄漏问题

大家都知道内存泄漏和内存溢出是不一样的,内存泄漏所导致的越来越多的内存得不到回收的失手,最终就有可能导致内存溢出,下面说一下使用staitc属性所导致的内存泄漏的问题. 在dalvik虚拟机中,static变量所指向的内存引用,如果不把它设置为null,GC是永远不会回收这个对象的,所以就有了以下情况: [java] view plain copy public class SecondActivity extends Activity{ private Handler mHandler = n

Dictionary带来的一种隐式内存泄漏

当心Dictionary带来的一种隐式内存泄漏 最近在看Dictionary的源代码的时候, 突然想到Dictionary的不当使用中有一种隐含内存泄漏的可能. 简化使用场景 小A正在写一个简单的图书销售系统. 他首先需要处理的是订单和订单里面对应的书目集合. 接着他发现自己需要一个特定的内存结构, 来临时保存所有的订单及其伴随的销售书目集合, 以减小对数据库的压力. 小A想到了词典Dictionary这个保存关联数据最好用的结构 - 将订单Order对象做为键, 将对应的销售书目Books作为

ReportViewer内存泄漏问题解决方案[上]

做这个项目有点倒霉,快要验收的时候,发现微软ReportViewer控件的一个bug,导致我们的项目无法正常验收. 问题描叙:用ReportViewer本地模式做的报表,在ASP.NET页面中呈现.在asp.net服务端有一个静态页面,用户轮播报表页面.这些页面被加载到一个盒子里面,然后在电视上面显示.最终电视就可以看到我们报表轮回的切换.在推广的过程中,电视终端越来越多,暴露出一个问题,报表播放久了就会出现内存溢出的问题. 后来查资料,显示ReportViewer确实存在内存泄漏的问题,该如何

Handler可能导致的内存泄漏及其优化

package cc.cc; import java.lang.ref.WeakReference; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; /** * Demo描述: * Handler可能导致的内存泄露及其优化 * * 1 关于常见的Handler的用法但是可能导致内存泄露 * 请参考方法initHandler()

在Activity中使用Thread导致的内存泄漏

原文链接 : Activitys, Threads, & Memory Leaks 原文作者 : AlexLockwood 译文出自 : 开发技术前线 www.devtf.cn 译者 : chaossss 校对者: yinna317 状态 : 完成 注:这篇博文涉及的源码可以在 GitHub 上面下载哦 做 Android 开发最常遇到的问题就是在 Activity 的生命周期中协调耗时任务,避免执行任务导致不易察觉的内存泄漏.不妨先读一读下面的代码,代码写了一个简单的 Activity,Act

非静态内部类可能导致的内存泄漏及其优化

package cc.cc; import android.os.Bundle; import android.app.Activity; /** * Demo描述: * 非静态内部类可能导致的内存泄露及其优化 * * 在MainActivity中定义了两个内部类InnerClassTest和ThreadSubClass. * 在这里需要注意一个问题: * 内部类持有外部类的引用!!!! * 或者说内部类对外部类持有隐式的引用!!!! * * 假如我们在内部类中做耗时的操作或者说有个while(