Android 应用程序内存泄漏的分析

合集下载

Android内存泄漏终极解决方法介绍

Android内存泄漏终极解决方法介绍

Android内存泄漏终极解决方法介绍Android内存泄漏终极解决方法介绍一、概述在Android内存泄漏终极解决篇(上)中我们介绍了如何检查一个App是否存在内存泄漏的问题,本篇将总结典型的内存泄漏的代码,并给出对应的解决方案。

内存泄漏的主要问题可以分为以下几种类型:静态变量引起的内存泄漏非静态内部类引起的内存泄漏资源未关闭引起的内存泄漏二、静态变量引起的内存泄漏在java中静态变量的生命周期是在类加载时开始,类卸载时结束。

换句话说,在android中其生命周期是在进程启动时开始,进程死亡时结束。

所以在程序的运行期间,如果进程没有被杀死,静态变量就会一直存在,不会被回收掉。

如果静态变量强引用了某个Activity中变量,那么这个Activity就同样也不会被释放,即便是该Activity执行了onDestroy(不要将执行onDestroy和被回收划等号)。

这类问题的解决方案为:1.寻找与该静态变量生命周期差不多的替代对象。

2.若找不到,将强引用方式改成弱引用。

比较典型的例子如下:单例引起的Context内存泄漏public class IMManager { private Context context; private static IMManager mInstance; public static IMManager getInstance(Context context) { if (mInstance == null) { synchronized (IMManager.class) { if (mInstance == null) mInstance = new IMManager(context); } } return mInstance; } private IMManager(Context context) { this.context = context; }} 当调用getInstance时,如果传入的context是Activity的'context。

详解Android内存泄露及优化方案

详解Android内存泄露及优化方案

详解Android内存泄露及优化⽅案⽬录⼀、常见的内存泄露应⽤场景?1、单例的不恰当使⽤2、静态变量导致内存泄露3、⾮静态内部类导致内存泄露4、未取消注册或回调导致内存泄露5、定时器Timer 和 TimerTask 导致内存泄露6、集合中的对象未清理造成内存泄露7、资源未关闭或释放导致内存泄露8、动画造成内存泄露9、WebView 造成内存泄露总结⼀、常见的内存泄露应⽤场景?1、单例的不恰当使⽤单例是我们开发中最常见和使⽤最频繁的设计模式之⼀,所以如果使⽤不当就会导致内存泄露。

因为单例的静态特性使得它的⽣命周期同应⽤的⽣命周期⼀样长,如果⼀个对象已经没有⽤处了,但是单例还持有它的引⽤,那么在整个应⽤程序的⽣命周期这个对象都不能正常被回收,从⽽导致内存泄露。

如:public class App {private static App sInstance;private Context mContext;private App(Context context) {this.mContext = context;}public static App getInstance(Context context) {if (sInstance == null) {sInstance = new App(context);}return sInstance;}}调⽤getInstance(Context context)⽅法时传⼊的上下⽂如果为当前活动Activity或者当前服务的Service以及当前fragment的上下⽂,当他们销毁时,这个静态单例sIntance还会持⽤他们的引⽤,从⽽导致当前活动、服务、fragment等对象不能被回收释放,从⽽导致内存泄漏。

这种上下⽂的使⽤很多时候处理不当就会导致内存泄漏,需要我们多注意编码规范。

2、静态变量导致内存泄露静态变量存储在⽅法区,它的⽣命周期从类加载开始,到整个进程结束。

Android内存管理、泄漏调试技巧

Android内存管理、泄漏调试技巧

内存泄漏情况再分析
• 常见的内存泄漏情况 • JNI层内存泄漏
• 如果分析不出来,需要通过MAT工具进行进 一步的查找。
MAT(Memory Analyzer Tool)
• 下载HPROF文件。 • 使用Eclipse Memory Analyzer工具打开。 • 如果无法打开需要使用Android自带的hprof-
conv.exe 工具进行转换。
• 抓取两份hprof文件,操作一两次,case gc 抓取第一份,重复多次有内存泄漏的操作, case gc 抓取第二份。
分析步骤
• 以查询光标没有关闭导致内存泄漏为例
– 利用Heap,找到内存泄漏的操作。(先要作GC)
分析步骤
• 使用Allocation Tracker对这一操作进行跟踪;重点查 看相同行中多次申请的操作,结合代码分析。
• Allocation Tracker工具只反映出了Allocation 的操作记录。有可能显示出来的对象其实 已经释放或者会被GC。
• 不同类型的进程有不同的内存使用上限。
– init.rc
引起内存泄漏的情况
• 查询数据库没有关闭游标
Cursor cursor = null; try {
cursor = getContentResolver().query(uri ...); if (cursor != null && cursor.moveToNext()) {
但是如果在释放LockScreen 对象的时候忘记取消我们之前 注册的PhoneStateListener 对象,则会导致LockScreen 无法被垃 圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大 量的LockScreen 对象没有办法被回收而引起OutOfMemory,使得 system_process 进程挂掉。

AndroidHandler内存泄漏详解及其解决方案

AndroidHandler内存泄漏详解及其解决方案

AndroidHandler内存泄漏详解及其解决⽅案关联篇:关联篇:在android开发过程中,我们可能会遇到过令⼈奔溃的OOM异常,⾯对这样的异常我们是既熟悉⼜深恶痛绝的,因为造成OOM 的原因有很多种情况,如加载图⽚过⼤,某已不再使⽤的类未被GC及时回收等等......本篇我们就来分析其中⼀种造成OOM的场景,它就是罪恶的内存泄漏。

对于这样的称呼,我们并不陌⽣,甚⾄屡次与之"并肩作战",只不过它就是⼀个猪队友,只会不断送塔.......本篇分为3部分:1.Handler内存泄漏例⼦说明以及原理阐明2.问题验证(如果感觉繁琐请直接跳过)3.Handler内存泄漏解决⽅法1.Handler内存泄漏例⼦说明以及原理阐明Handler,我们已经相当熟悉了,⽽且经常⽤得不亦乐乎,但就是因为太熟悉了,才会偶尔被它反捅⼀⼑,⾎流不⽌......还记得我们曾经满怀信⼼地使⽤着如下的优美⽽⼜简洁的代码不?不怕你吓着,实话告诉你,这个代码已经造成内存泄漏了不相信?我们使⽤Android lint⼯具检测⼀下该类的代码:⾯对现实吧,那为什么会这样呢?在java中⾮静态内部类和匿名内部类都会隐式持有当前类的外部引⽤,由于Handler是⾮静态内部类所以其持有当前Activity的隐式引⽤,如果Handler没有被释放,其所持有的外部引⽤也就是Activity也不可能被释放,当⼀个对象⼀句不需要再使⽤了,本来该被回收时,⽽有另外⼀个正在使⽤的对象持有它的引⽤从⽽导致它不能被回收,这导致本该被回收的对象不能被回收⽽停留在堆内存中,这就产⽣了内存泄漏(上⾯的例⼦就是这个原因)。

最终也就造成了OOM.......我们再来段清晰的代码,我们来使⽤mHandler发送⼀个延迟消息:分析:当我们执⾏了HandlerActivity的界⾯时,被延迟的消息会在被处理之前存在于主线程消息队列中5分钟,⽽这个消息中⼜包含了Handler的引⽤,⽽我们创建的Handler⼜是⼀个匿名内部类的实例,其持有外部HandlerActivity的引⽤,这将导致了HandlerActivity⽆法回收,进⾏导致HandlerActivity持有的很多资源都⽆法回收,从⽽就造成了传说中的内存泄露问题!2.问题验证(如果感觉繁琐请直接跳过)为了进⼀步验证内存泄漏问题,我们在该类中创建⼀个int数组,该数组分配的内存⼤⼩为2m,然后我们⽤DDMS来查看heap内存,然后使⽤GC回收,看看内存会不会有变化:第⼀次启动app时,head内存为12.5M,已经分配内容(Allocated):8.5M,空闲内存:4M,我们频繁点击GC按钮,内存并没有发⽣明显变化,现在我们点击⼿机返回健,推出应⽤,然后再重新进⼊,同样检测⼀下head内存:我们发现head内存:20.5M,Allocated:16.5M,Free:4M,堆内存和已经分配内存近乎翻倍,我们继续频繁点击GC, 看看能否被回收?结果内存并没有明显变化,现在我们继续点击⼿机返回健,推出应⽤,然后再重新进⼊,同样再次检测⼀下head内存:我们发现head内存:28.5M,Allocated:24.5M,Free:4M,堆内存和已经分配内存⼜增加了,⽽且⽆论我们如何点击GC回收内存,内存都没有明显变化,⽽且每启动⼀次该页⾯,内存就增加⼀倍!这也就说存在在某个类只创建⽽没销毁的情况,其实就是存在内存泄漏问题。

移动应用中的内存泄漏分析

移动应用中的内存泄漏分析

移动应用中的内存泄漏分析在现代社会中,移动应用成为人们生活中不可或缺的一部分。

开发一个高品质的移动应用需要开发人员关注各个方面的问题,其中,内存泄漏是其中之一。

内存泄漏是移动应用中经常遇到的问题,它会导致应用程序内存占用过多,使应用程序运行时变得缓慢或崩溃。

本文将介绍移动应用中的内存泄漏问题,并提供了解决内存泄漏难题的方法。

什么是内存泄漏?内存泄漏是指应用程序在使用内存时没有正确地管理内存的释放。

当应用程序需要分配动态内存时,操作系统会在堆中分配一块内存。

当应用程序使用完该内存时,应该通过释放函数来释放这块内存以便应用程序后续的内存使用。

当应用程序没有正确释放该内存时,这块内存就被占用,这就是内存泄漏。

内存泄漏的原因在移动应用中,内存泄漏的原因可能有很多,有些是由于开发人员不小心编写的代码造成的,而有些则是由于操作系统引起的。

以下是一些可能导致内存泄漏的原因:1. 对象生命周期问题创建的对象一定要在使用完之后释放。

如果对象没有被正确的释放,那么这个对象所占用的内存就会被浪费掉,从而导致内存泄漏。

内存泄漏主要是由于程序没有删除已经创建的对象或没有正确使用指针来引用这些对象。

2. 指针操作指针是一个指向另外一个内存区域的变量。

对于指针而言,它必须指向合适的内存区域。

如果程序没有正确使用指针来引用对象,那么可能会发生内存泄漏。

解决内存泄漏问题的方法以下是几种解决内存泄漏问题的方法:1. 使用工具检测工具可以检测应用程序中的内存泄漏。

有许多内存泄漏检测工具可供选择,例如,MallocDebug、MemoryChecker等工具。

使用这些工具可以帮助开发人员快速和准确地识别并处理内存泄漏的问题。

2. 使用显式释放函数显式释放函数在使用完一个对象时,会自动将其从内存中删除。

显式释放函数还可以确保内存释放的准确性,从而避免因为对象过早地被删除而导致的重复释放错误。

3. 确保对象生命周期的正确性确保对象的生命周期正确性需要开发人员仔细地检查和设计代码。

Android内存泄漏研究

Android内存泄漏研究

Android内存泄漏研究By Jason Ross1月 6 2015 更新日期:1月 6 2015概念根搜索算法Android虚拟机的垃圾回收采用的是根搜索算法。

GC会从根节点(GC Roots)开始对heap进行遍历。

到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉。

根搜索算法相比引用计数法很好的解决了循环引用的问题。

举个例子,Activity有View的引用,View也有Activity的引用,之前我还尝试去源代码里找Activity何时和View断开连接是大错特错了。

当Activity finish掉之后,Activity和View的循环引用已成孤岛,不再引用到GC Roots,无需断开也会被回收掉。

内存泄漏Android内存泄漏指的是进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到gc roots导致无法被GC回收。

无用的对象占据着内存空间,使得实际可使用内存变小,形象地说法就是内存泄漏了。

场景类的静态变量持有大数据对象静态变量长期维持到大数据对象的引用,阻止垃圾回收。

非静态内部类的静态实例非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。

资源对象未关闭资源性对象如Cursor、File、Socket,应该在使用后及时关闭。

未在finally中关闭,会导致异常情况下资源对象未被释放的隐患。

注册对象未反注册未反注册会导致观察者列表里维持着对象的引用,阻止垃圾回收。

Handler临时性内存泄露Handler通过发送Message与主线程交互,Message发出之后是存储在MessageQueue中的,有些Message也不是马上就被处理的。

在Message中存在一个 target,是Handler的一个引用,如果Message在Queue中存在的时间越长,就会导致Handler无法被回收。

安卓内存泄漏分析ANDROID MEMORY LEAK ANALYSIS GUIDE

安卓内存泄漏分析ANDROID MEMORY LEAK ANALYSIS GUIDE

Confidential and Proprietary – Qualcomm Technologies, Inc.
Confidential and Proprietary – Qualcomm Technologies, Inc.
NO PUBLIC DISCLOSURE PERMITTED: Please report postings of this document on public servers or websites to: DocCtrlAgent@. Restricted Distribution: Not to be distributed to anyone who is not an employee of either Qualcomm or its subsidiaries without the express approval of Qualcomm’s Configuration Management. Not to be used, copied, reproduced, or modified in whole or in part, nor its contents revealed in any manner to others without the express written permission of Qualcomm Technologies, Inc. Qualcomm reserves the right to make changes to the product(s) or information contained herein without notice. No liability is assumed for any damages arising directly or indirectly by their use or application. The information provided in this document is provided on an “as is” basis. This document contains confidential and proprietary information and must be shredded when discarded. Qualcomm is a trademark of QUALCOMM Incorporated, registered in the United States and other countries. All QUALCOMM Incorporated trademarks are used with permission. Other product and brand names may be trademarks or registered trademarks of their respective owners. This technical data may be subject to U.S. and international export, re-export, or transfer (“export”) laws. Diversion contrary to U.S. and international law is strictly prohibited. Qualcomm Technologies, Inc. 5775 Morehouse Drive San Diego, CA 92121 U.S.A. © 2013 Qualcomm Technologies, Inc. All rights reserved.

Android内存泄漏的原因及解决技巧

Android内存泄漏的原因及解决技巧

Android内存泄漏的原因及解决技巧正确的⽣命周期管理如何防⽌Android内存泄漏OutOfMemoryException是⼀个常见的令⼈沮丧的错误,也是导致应⽤程序意外关闭的主要原因之⼀。

“如果应⽤程序昨天运⾏良好,为什么现在会发⽣这种情况?这个问题让Android的开发者和新⼿都感到困惑。

导致OutOfMemory异常的潜在原因有很多种,但其中最常见的是内存泄漏—应⽤程序中的内存分配从未释放。

本⽂将解释如何通过有效的⽣命周期管理(开发过程中⼀个重要但经常被忽视的部分)来最⼩化这种风险。

为什么安卓系统会发⽣内存泄漏?问题很简单。

某些对象应该只有⼀个固定的寿命,当它们的使⽤寿命结束时,它们需要被删除。

理论上,当进程使⽤onStop或onDestroy终⽌时,应该处理该内存。

但是,滥⽤对象引⽤可能会阻⽌垃圾收集器释放未使⽤的对象。

例如:如果未使⽤的对象A引⽤了未使⽤的对象B,那么您将得到两个不必要的对象,垃圾回收器将永远不会释放它们,因为它们正在相互引⽤。

阻⽌内存泄漏这种情况发⽣的常见技巧开发⼈员可以采取许多步骤来阻⽌死的活动被困在内存中。

1. 在onResume()/onPause()或onStart()/onStop()中注册/注销⼴播接收器2. 不要对视图/活动/上下⽂使⽤静态变量3. 需要保存对上下⽂的引⽤的singleton应该使⽤applicationContext()或将其包装到WeakReference中4. 注意匿名和⾮静态内部类,因为它们包含对其封闭类的隐式引⽤。

5. 如果要⽐⽗类(如处理程序)更长寿,请使⽤静态内部类⽽不是匿名类。

6. 如果内部或匿名类是可取消的(如AsyncTask、Thread、RxSubscriptions),则在销毁活动时取消它。

Android⽣命周期感知组件⼀旦你完成了上⾯的基本步骤,现在是时候做⼀些更重要的事情了:应⽤程序活动的⽣命周期。

如果我们不能正确地管理⽣命周期,我们最终会在不再需要内存的时候挂掉它。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Android 应用程序内存泄漏的分析
以前在学校里学习Java的时候,总是看到说,java是由垃圾收集器(GC)来管理内存回收的,
所以当时形成的观念是Java不会产生内存泄漏,我们可以只管去申请内存,不需要关注内存回收,
GC会帮我们完成。呵呵,很幼稚的想法,GC没那么聪明啊,理论及事实证明,我们的Java程序也
是会有内存泄漏的。

(一) Java内存泄漏从何而来
一般来说内存泄漏有两种情况。一种情况如在C/C++语言中的,在堆中的分配的内存,没
有将其释放,或者是在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指
针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它
的访问方式(引用)。第一种情况,在Java中已经由于垃圾回收机制的引入,得到了很好的解
决。所以,Java中的内存泄漏,主要指的是第二种情况。

(二) 需要的工具
1. DDMS—Update heap Gause GC
Heap 是DDMS自带的一个很不错的内存监控工具,下图红色框中最左边的图标就是该
工具的启动按钮,它能在Heap视图中显示选中进程的当前内存使用的详细情况。下图
框中最右边的是GC工具,很多时候我们使用Heap监控内存的时候要借助GC工具,点
击一次GC按钮就相当于向VM请求了一次GC操作。中间的按钮是Dump HPROF file,它
的功能相当于给内存拍一张照,然后将这些内存信息保存到hprof文件里面,在使用我
们的第二个工具MAT的时候会使用到这个功能。

2. MAT(Memory Analyzer Tool)
Heap工具能给我们一个感性的认识,告诉我们程序当前的内存使用情况和是否存在内存
泄漏的肯能性。但是,如果我们想更详细,更深入的了解内存消耗的情况,找到问题所
在,那么我们还需要一个工具,就是MAT。这个工具是需要我们自己去下载的,可以下
载独立的MAT RCP 客户端,也可以以插件的形式安装到Eclipse里面,方便起见,推荐
后者。
安装方法:
A. 登录官网http://www.eclipse.org/mat/downloads.php
B. 下载MAT Eclipse插件安装包(红框所示,当然你也可是选择Update Site在线安装,
个人觉得比较慢)
C. 安装
在Eclipse里面安装新软件,选择刚才下载的本地安装包进行安装

(三) 案例分析
工具准备好了,那就来看看怎么使用。我们以Q+ for Pad为例,看看查找好友功能是否存在
内存泄漏。
1. 打开 eclipse 并切换到 DDMS 透视图,同时确认 Devices 、 Heap 和 logcat 视图已经打

开了。
2. 将Pad设备链接到电脑,并确保使用“ USB 调试”模式链接
3. 启动我们的Q+ for Pad应用,此时我们能看到下图所示的情况,Q+ Pad有两个进程

4. 选中main进程,点击Update Heap按钮,再点击GC按钮,查看该进程当前堆内存的使用
情况
如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:Heap视
图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类
型的对象。在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java
数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样
判断:
a) 不断的操作当前应用,同时注意观察data object的Total Size值;
b) 正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代
码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成
很多对象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会
会落到一个稳定的水平;
c) 反之如果代码中存在没有释放对象引用的情况,则data object的Total Size值在每
次GC后不会有明显的回落,随着操作次数的增多Total Size的值会越来越大,直到到
达一个上限后导致进程被kill掉。
5. 输入昵称,查找联系人,在查到的结果中不断向下翻页,最后退出(这个时候程序会不

断的拉取联系人的头像,这是我们要关注的),然后我们点击下GC按钮,手动触发下垃
圾回收,结果截图如下,图中红色标记的地方可以看出,执行查找联系人操作后,这两
个数值明显增加了,GC操作也无法使之下降,我们可以怀疑,这个操作导致了内存泄漏。

6. 使用MAT进一步分析,找到问题的根源。之前我们已经安装了MAT插件,所以这里我
们只要选中main进程,点击Dump HPROF file按钮,就会跳转到MAT视图。在弹出的对
话框中选择报告类型,一般选第一个就行。

点击完成后,MAT会自动生成报告,列出几个内存占用比较大的可疑对象,MAT不会明
确告诉我们这就是泄露,因为它也不知道这个东西是不是程序还需要的,只有程序员自
己知道。图中很明显的占用内存较大的是头像资源,并且当退出查找联系人功能后,这
些资源是需要释放的,陌生人的头像我们不需要缓存在内存里面。
点击Domain Tree按钮,可以按包进行分组。点开树形列表,可以更详细的看到类对象
占用内存的大小。其中,Shallow Heap表示实例的内存使用总和,Retained Heap表示所
有类实例被分配的内存总和,里面也包括他们所有引用的对象。

从生成的数据中,我们发现有一千多个HashMapEntry对象,针对单个HashMapEntry对
象继续追踪,最后找到了一个6KB左右的Bitmap,应该就是我们的头像资源。

因此,为了回收内存,我们必须把刚才查找好友保存在内存中的头像资源释放。通过使
用Heap 和MAT工具,能够更好的帮助测试人员发现及定位内存泄漏问题,也能帮助我
们发下性能问题,找到内存优化的点。

相关文档
最新文档