Android内存泄漏的简单检查与分析方法

简介: 内存泄漏问题大约是Android开发者最烦恼的问题之一了,项目中连续遇到几个内存泄漏问题,这里简单总结下检查分析内存泄漏的一些工具与方法。

一、什么是内存泄漏?

大家都知道,java是有垃圾回收机制的,这使得java程序员比C++程序员轻松了许多,存储申请了,不用心心念念要加一句释放,java虚拟机会派出一些回收线程兢兢业业不定时地回收那些不再被需要的内存空间(注意回收的不是对象本身,而是对象占据的内存空间)。

Q1:什么叫不再被需要的内存空间?

**答:**Java没有指针,全凭引用来和对象进行关联,通过引用来操作对象。如果一个对象没有与任何引用关联,那么这个对象也就不太可能被使用到了,回收器便是把这些“无任何引用的对象”作为目标,回收了它们占据的内存空间。

Q2:如何分辨为对象无引用?

**答:**2种方法

  1. 引用计数法 直接计数,简单高效,Python便是采用该方法。但是如果出现 两个对象相互引用,即使它们都无法被外界访问到,计数器不为0它们也始终不会被回收。为了解决该问题,java采用的是b方法。

  2. 可达性分析法 这个方法设置了一系列的“GC Roots”对象作为索引起点,如果一个对象 与起点对象之间均无可达路径,那么这个不可达的对象就会成为回收对象。这种方法处理 两个对象相互引用的问题,如果两个对象均没有外部引用,会被判断为不可达对象进而被回收(如下图)。

1.png

Q3:有了回收机制,放心大胆用不会有内存泄漏?

**答:**答案当然是No!

虽然垃圾回收器会帮我们干掉大部分无用的内存空间,但是对于还保持着引用,但逻辑上已经不会再用到的对象,垃圾回收器不会回收它们。这些对象积累在内存中,直到程序结束,就是我们所说的“内存泄漏”。

当然了,用户对单次的内存泄漏并没有什么感知,但当泄漏积累到内存都被消耗完,就会导致卡顿,崩溃。

二、发现内存泄漏

内存泄漏不可小视,在Android开发中,比如说一个Activity页面会占用许多资源开销,如果页面发生泄漏,关闭以后页面没有能被系统回收,对应用程序的伤害是很大的。

Q1:在Android开发测试中一般如何发现内存泄漏的发生呢?

答:

方法1:反复操作观察内存变化

内存泄漏常见变现为程序使用时间越长,内存占用越多。那我们通过反复操作应用,比如反复点开/关闭页面,观察内存变化状况是否一点点上涨,可以粗略地判断是否有内存泄漏

1.通过 DDMS 中的 heap 工具,可以查看应用内存的使用情况

2.png

2.Android studio也可以方便查看

3.jpg

方法2:通过代码检测Activity泄漏

基本思路:

1)debug版本可以起一个长期工作的线程LeakThread在后台专门做泄漏检测

2)向Application注册一个 页面生命周期 的监听:application.registerActivityLifecycleCallbacks

3)在监听类中对 onActivityDestoryed(Activity activity) 的事件回调做处理:

如果一个Activity走到onDestroy,那么这个Activity对象就是需要被回收的目标。

我们声明一个检测对象的弱引用ref = new WeakReference<Object>(activity)。

**PS:**与强引用和软引用相比,弱引用不会被回收器当做一个“有效”的引用,不会影响其引用对象的释放。实际上,垃圾回收器会毫不犹豫地回收只有弱引用的对象~

4)在 LeakThread中我们每隔一段时间检测一下ref.get() 是否为空,为空说明activity已被释放。不为空可以手动触一次发gc;如果超过一段时间,比如50s,页面对象还未被清理,我们可以推断内存泄漏的发生.

5)当内存泄漏发生时,提示给开发者,并自动dump出.prof文件。

因为代码检测不是这里的重点,代码就不贴了,只记思路。

三、分析内存泄漏(DDMS dump + MAT分析)

发现可能出现内存泄漏时,我们需要对.prof文件进行分析,方能快速定位到是哪个倒霉家伙导致了内存泄漏

3.1、如何dump出.prof文件?(可参照前文图片)

  1. 打开DDMS ,Eclipse 可以切到DDMS视图,Android studio可以从Tools-Android-Android device monitor进入DDMS

  2. 找到app的进程,在进程上方点击“update heap”按钮,可以先主动出发一次GC,待内存占用数据稍微稳定下来后 点击“Dump HProf File”,便可以导出.prof文件

3.2:导出.prof文件后如何分析?

Android studio可以直接打开prof文件。点开Analyzer Tasks的面板,点击右上角的开始按钮。

4.jpg

分析完成后,发生内存泄漏的页面对象会出现在Analysis Results面板-Leak Activityes的目录下。

如图,原来泄漏发生是LoadingRoomActivity的锅!

5.jpg

3.3 进一步分析泄漏的原因,你会需要一个好用的内存分析工具:MAT

在官网可以下载到它:

http://www.eclipse.org/mat/downloads.php

虽然MAT不会准确告诉你你的代码哪泄漏了,但是它会给你发现哪泄露的数据和线索。

3.3.1 打开.hprof前可能遇到的问题:

在MAT中打开.prof页面,你可能会遇到一点小挫折:

6.png

如上图,可能会弹出 ‘Parsing heap dump from xxx has encountered a proplem’ 的错误弹窗

这是因为文件版本和编辑器能支持的版本有冲突的原因。

解决方案如下:

Sdk安装目录下platform-tools里有一个hprof-conv工具可以解决该问题。在cmd控制台执行:

hprof-conv input.hprof output.hprof

重新再MAT打开output.hprof 就可以打开了~

值得一提的是,如果你dump出的文件太大的话,也有可能发现打不开的现象,这时候,打开安装MAT目录下的MemoryAnalyzer.ini 把-XmX改大些重启即可。但是也不要改得比你机器的可用内存还大,不能太贪心哈哈~

7.png

3.3.2 打开.phrof文件后的分析

通过MAT打开.phrof文件后,会弹出Overview 和 Leak Suspects 2个标签页。

Leak Suspects标签页可见如下图:

8.png

Leak Suspects视图展示了app内存占用的比例,浅色是空闲的内存,其他是内存占用的空间。每块内存对应的问题也都列在下面。点开每个Problem Suspect下的details,可以看到有哪些类的实例占用了内存和占用大小等信息~

9.png

此时我们已经有了怀疑的目标,为了更清晰地查看,我们可以回到Overview页面,打开Histogram页面:

10.png

在打开的Histogram标签页中,我们填入检测对象,在列出的匹配项中过滤掉对象的非强引用。

11.jpg

到这里我们就可以看到,是哪个坏蛋hold住了你的对象了。MAT能够给到的支持也就到这里,接下来,还是需要你根据这些线索到代码中寻找判别和修正了~``

12.png

目录
相关文章
|
6天前
|
Java Android开发 iOS开发
深入探讨移动操作系统的性能优化:安卓与iOS的对比分析
在现代移动设备中,操作系统的性能优化至关重要。本文从系统架构、内存管理、电池续航和应用程序运行效率等多个维度,深入探讨了安卓(Android)和iOS两大主流移动操作系统的优化策略及其实际效果,旨在为开发者和用户提供更清晰的了解和选择依据。
17 0
|
20天前
|
存储 开发工具 Android开发
构建高效的Android应用:从内存管理到用户界面
【5月更文挑战第29天】 随着智能手机的普及,Android应用的开发变得日益重要。然而,许多开发者在开发过程中忽视了性能优化,导致应用运行缓慢,用户体验差。本文将深入探讨如何通过有效的内存管理和用户界面优化,提升Android应用的性能。我们将详细介绍内存泄漏的原因和解决方案,以及如何使用Android的新特性来创建流畅的用户界面。无论你是新手还是经验丰富的开发者,都可以从本文中获得有用的技巧和建议。
|
3天前
|
安全 Android开发 iOS开发
探索Android与iOS开发的差异:平台特性与用户体验的对比分析
在移动应用开发的广阔天地中,Android和iOS两大阵营各据一方。本文将深入探讨这两个操作系统在开发环境、编程语言、用户界面设计及市场分布等方面的主要区别。通过比较分析,我们将揭示各自平台的特有优势,并讨论如何根据目标受众和业务需求选择适合的开发平台。
|
3天前
|
程序员 C语言 C++
【C语言基础】:动态内存管理(含经典笔试题分析)-2
【C语言基础】:动态内存管理(含经典笔试题分析)
|
3天前
|
程序员 编译器 C语言
【C语言基础】:动态内存管理(含经典笔试题分析)-1
【C语言基础】:动态内存管理(含经典笔试题分析)
|
6天前
|
搜索推荐 安全 Android开发
安卓与iOS操作系统的对比分析
在移动设备市场上,安卓和iOS操作系统一直是主要竞争对手。本文将从用户界面、应用生态系统、定制化程度和安全性等方面对安卓和iOS进行对比分析,并探讨两者在不同场景下的适用性。
|
12天前
|
编解码 缓存 Android开发
构建高效的Android应用:从内存优化到响应式设计
【5月更文挑战第37天】 在竞争激烈的移动应用市场中,一个高效、流畅的Android应用是吸引和保留用户的关键。本文将深入探讨构建高效Android应用的多个关键方面,包括内存优化策略、布局性能和响应式设计原则。我们将通过具体的技术实践和案例分析,揭示如何提升应用性能,减少资源消耗,并确保在不同设备上的兼容性和用户体验一致性。
|
12天前
|
安全 Android开发 iOS开发
安卓与iOS操作系统的比较分析
【6月更文挑战第5天】本文将深入探讨安卓和iOS两大主流操作系统的特点、优势和劣势。通过对比分析,我们将揭示这两个系统在性能、安全性、用户体验等方面的差异,帮助用户更好地了解这两个系统,从而做出更明智的选择。
|
16天前
|
C++ 存储 Java
C++ 引用和指针:内存地址、创建方法及应用解析
'markdown'C++ 中的引用是现有变量的别名,用 `&` 创建。例如:`string &meal = food;`。指针通过 `&` 获取变量内存地址,用 `*` 创建。指针变量存储地址,如 `string *ptr = &food;`。引用不可为空且不可变,指针可为空且可变,适用于动态内存和复杂数据结构。两者在函数参数传递和效率提升方面各有优势。 ```
|
19天前
|
缓存 监控 Android开发
Android 开发中的内存优化策略
【5月更文挑战第30天】在移动应用的开发过程中,性能和用户体验始终是核心关注点。对于基于Android平台的应用程序,有效的内存管理是确保流畅运行和优异性能的关键因素之一。本文将深入探讨Android开发中常见的内存问题,并提出一系列实用的内存优化策略。我们将从内存泄漏的识别与防止开始,到合理使用内存缓存技巧,以及高效的数据结构选择等方面进行详细阐述。通过这些策略的实施,开发者可以显著减少应用的内存占用,提升应用的稳定性和响应速度,进而改善最终用户的体验。