android studio利用leak怎么检测android mvp 内存泄漏漏

他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Android 深入理解LeakCanary的内存泄露检测机制(中)
上篇文章主要介绍了内存分配相关的知识以及在开发中可能遇见的各种内存泄露情况并给出了相对应的解决方案,如果你还没有看过上篇文章,建议点击这里一下,这篇文章我将要向大家介绍如何在我们的应用中使用square开源的LeakCanary库来检测应用中出现的内存泄露,如果你已经对LeakCanary的使用非常熟悉了请跳过本文(*^__^*) &&
以介绍来自英文的翻译,原文在这里。
java.lang.OutOfMemoryError
at android.graphics.Bitmap.nativeCreate(Bitmap.java:-2)
at android.graphics.Bitmap.createBitmap(Bitmap.java:689)
at com.squareup.ui.SignView.createSignatureBitmap(SignView.java:121)
没人喜欢OutOfMemoryError
在Square Register中,在签名页面我们把画在bitmap cache上,这个Bitmap的尺寸几乎和屏幕的尺寸一样大,在创建这个Bitmap对象时,经常会引发OutOfMemoryError,简称OOM。
当时,我们尝试过一些解决方案,但是都没解决问题:
使用Bitmap.Config.ALPHA_8,因为签名仅有黑色。捕捉OutOfMemoryError,尝试GC并重试(受启发)。我们没想过在Java Heap内存之外创建Bitmap,苦逼的我们,那会等库还不存在。
路子走错了
其实Bitmap的尺寸不是真正的问题,当内存吃紧的时候,到处都有可能引发OOM,在创建大对象,比如Bitmap的时候,则更有可能引发OOM,OOM只是一个表象,更深层次的问题可能是:内存泄露。
什么是内存泄露
一些对象有着有限的声明周期,当这些对象所要做的事情完成了,我们希望它们会被垃圾回收器回收掉。但是如果有一系列对这个对象的引用存在,那么在我们期待这个对象生命周期结束时被垃圾回收器回收的时候,它是不会被回收的。它还会占用内存,这就造成了内存泄露。持续累加,内存很快被耗尽。
比如:当Activity的onDestroy()方法被调用后,Activity以及它涉及到的View和相关的Bitmap都应该被回收掉。但是,如果有一个后台线程持有这个Activity的引用,那么该Activity所占用的内存就不能被回收,这最终将会导致内存耗尽引发OOM而让应用crash掉。
对战内存泄露
排查内存泄露是一个全手工的过程,这在Raizlabs的系列文章中有详细描述。以下几个关键步骤:
通过,或者等统计平台,了解OutOfMemoryError情况。重现问题。为了重现问题,机型非常重要,因为一些问题只在特定的设备上出现。为了找到特定的机型,你需要想尽一切办法,你可能需要去买,去借,甚至去偷。当然,为了确定复现步骤,你需要一遍一遍地去尝试。一切都是非常原始和粗暴的。在发生内存泄露的时候,把内存Dump出来。具体看。然后,你需要在或者之类的内存分析工具中反复查看,找到那些原本该被回收掉的对象。计算这个对象到GC Roots的最短强引用。确定应用路径中的哪个应用是不该有的,然后修复。
很复杂吧?如果有一个类库能在发生OOM之前把这些事情全部搞定,然后你只要修复这些问题就好了,岂不美哉!!!这就是LeakCanary的由来,接下来我们就要介绍一下LeakCanary的使用。
由于Google已经不再对Eclipse上开发Android做支持,所以就不再Eclipse上演示如何使用LeakCanary了,LeakCanary的官方网址为:,根据指导文档,使用LeakCanary首先要引入,在build.gradle中添加依赖,如下所示:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
在build.gradle中添加了LeakCanary的依赖后,点击按钮同步一下工程后就可以使用LeakCanary了。细心的小伙伴可能会注意到我们引入了三种模式的依赖,debugCompile表示在debug打包模式下引入的依赖库,releaseCompile表示在release打包模式下引入的依赖库,testCompile表示的是在test打包模式引入的依赖库。总的来说就是在不同模式下使用不同的库,在项目打包的时候不会把其他模式的库打包进去。它们之间的区别稍后会有讲解。
引入了LeakCanary的依赖库后,接下来就是使用它了,根据GitHub上的指导文档,首先在我们的Application中初始化LeakCanary,如下所示:
public class ExampleApplication extends Application {
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
LeakCanary.install(this);
在初始化之前先是调用LeakCanary的静态方法isInAnalyserProcess()做过滤,如果该方法返回true就直接返回否则就执行LeakCanary的install()方法进行初始化工作。这样就完成了LeakCanary的初始化操作,是不是很简单?接下来我们测试一个例子,看看LeakCanary是如何检测内存泄露的,在上篇文章系列之&十二&从源码的角度深入理解LeakCanary的内存泄露检测机制(上)中讲解了Android开发中常见的内存泄露情形(如果你还没有看过请点击)。我们根据上篇文章任意举一例子:从当前MainActivity页面跳转到LeakActivity页面,在LeakActivity页面中模拟长耗时的任务,然后点击返回键返回到MainActivity页面,现在编写LeakActivity,代码如下:
public class LeakActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.leak_activity);
public void start(View view) {
new Thread() {
public void run() {
while (true) {
Thread.sleep(1000);
Log.e(getPackageName(), &LeakCanary -----&&&&& & + System.currentTimeMillis());
} catch (Exception e) {
}.start();
在LeakActivity中,当点击了按钮后就会启动一个新的匿名内部类线程并在线程中模拟了长耗时的操作,根据上篇文章的讲解,匿名内部类会默认持有当前MainActivity的引用,当点击返回按钮后LeakActivity本应该由进行回收,但是内部启动的线程还在继续执行操作就造成了LeakActivity所占用的内存资源得不到释放,就会造成内存泄露。然后运行一下程序,看看效果:
根据运行效果来看,在LeakActivity页面在点击按钮启动了线程后返回到主页面后,大约5秒钟后会弹出一个提示框,提示说在进行内存泄露检测,稍后你会发现在状态栏上弹出了一个Notification,我们展开这个Notification看看里边是啥东东:
弹出的Notification大致说了包名为com.example.leakcanary下的LeakActivity发生了内存泄露,泄露的内存大约是108KB,如果想要查看更为详细的内存泄露信息,可以点击查看,然后我们点击进去看看详细的内存泄露信息,如下所示:
内存泄露引用链清晰详细的列举了发生内存泄露的原因,根据这种引用关系我们可以很容易的定位到内存泄露点,然后修复这些泄露问题。怎么样?是不是很简单?从此可以对身边的小伙伴说:用了LeakCanary以后再也不怕内存泄露了(*^__^*) &&检测到LeakActivity发生了内存泄露,根据上篇文章的修复方法修改一下LeakActivity之后再运行程序就不会有Notification弹出了。
LeakCanary的使用就是这么简单,如果你还没使用过它强烈建议使用一次,相信你用过之后就会离不开它的(*^__^*) &&在我们引入LeakCanary的时候我们引入了三种不同模式的库,他们之间肯定是有区别的,下载完它的源码后,其结构图如下所示:
通过阅读LeakCanary的代码发现leakcanary-android是真正内存泄露分析库,而leakcanary-android-no-op只是一个空壳子,里边啥也没做。也就是说在打release包的时候LeakCanary库根本就不会打进去,所以不不用担心引入额外的方法,只有在debug或者test模式下LeakCanary库才会打包进APK。
首先看一下leakcanary-android下的AndroidManifest.xml文件,如下所示:
在配置文件中首先申请读写权限是为了存储堆内存信息到文件中便于在后台分析是否发生了内存泄露。接着是声明了两个Service,他们分别是HeapAnalyzerService和DisplayLeakService,HeapAnalyzerService添加了android:process=&:leakcanary&属性,那也就是说HeapAnalyzerService是运行在单独的进程中的,这样做的目的是不影响APP进程(比如给APP进程造成卡顿等影响),因此在初始化LeakCanary的时候首先是调用了LeakCanary的静态方法isInAnalyzerProcess()方法判断当前进程是否是分析进程,如果是分析进程就不需要在分析进程中做APP进程需要做的初始化操作,所以就直接返回。最后声明了两个Activity,DisplayLeakActivity主要是以列表的形式展示出做有发生过的内存泄露点,点击列表中的每一条信息时会进入内存泄露的详情页面,RequestStoragePermissionActivity根据名字就知道它是用来申请存储权限的,需要注意的是DisplayLeakActivity和RequestStoragePermissionActivity都声明了android:taskAffinity=&com.squareup.leakcanary&属性,这既是说它们是运行在新的TaskStack中的,如果你不熟悉taskAffinity属性,请看我之前写的一篇文章:。
了解了LeakCanary的相关配置后我们再看一下它的相关资源文件:
资源文件就不详细说明了,对于这些资源我们能做的就是如果不喜欢这些资源文件,我们可以在项目中把它替换掉。
由于篇幅原因,这里就不再过多的分析LeakCanary的源码了,在下篇文章中我将带领小伙伴们从源码的角度出发深入分析一下LeakCanary的内存泄露分析机制,敬请期待!!!最后感谢收看(*^__^*) &&主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
CSDN &《程序员》研发主编,投稿&纠错等事宜请致邮
你只管努力,剩下的交给时光!
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:www.xttblog.com。个人QQ群:、
个人大数据技术博客:http://www.iteblog.com
Android内存泄露 高质量app必须解决的问题。高级开发者必须会的技术点。推送使用好的工具来进行检测。博客分类:
接上篇:[Android] 内存泄漏调试经验分享 (一)
三、内存监测工具
无论怎么小心,想完全避免是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方。中的就带有一个很不错的内存监测工具这里我使用的插件,并以真机为例,在模拟器中的情况类似。用监测应用进程使用内存情况的步骤如下:
1. 启动后,切换到透视图,并确认视图、视图都是打开的;
2. 将手机通过链接至电脑,链接时需要确认手机是处于“调试”模式,而不是作为“”;
3. 链接成功后,在的视图中将会显示手机设备的序列号,以及设备中正在运行的部分进程信息;
4. 点击选中想要监测的进程,比如进程;
5. 点击选中视图界面中最上方一排图标中的“”图标;
6. 点击视图中的“”按钮;
7. 此时在视图中就会看到当前选中的进程的内存使用量的详细情况[如图所示]。
a) 点击“”按钮相当于向虚拟机请求了一次操作;
b) 当内存使用信息第一次显示以后,无须再不断的点击“”,视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;
c) 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。
如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:视图中部有一个叫做,即数据对象,也就是我们的程序中大量存在的类类型的对象。在一行中有一列是“”,其值就是当前进程中所有数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:
a) 不断的操作当前应用,同时注意观察的值;
b) 正常情况下值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;
c) 反之如果代码中存在没有释放对象引用的情况,则的值在每次后不会有明显的回落,随着操作次数的增多的值会越来越大,
直到到达一个上限后导致进程被掉。
d) 此处已进程为例,在我的测试环境中进程所占用的内存的的正常情况下会稳定在之间,而当其值超过后进程就会被。
总之,使用的视图工具可以很方便的确认我们的程序是否存在内存泄漏的可能性。
四、内存分析工具
如果使用确实发现了我们的程序中存在内存泄漏,那又如何定位到具体出现问题的代码片段,最终找到问题所在呢?如果从头到尾的分析代码逻辑,那肯定会把人逼疯,特别是在维护别人写的代码的时候。这里介绍一个极好的内存分析工具 。
MAT是一个插件,同时也有单独的客户端。官方下载地址、介绍和详细的使用教程请参见:,在此不进行说明了。另外在安装后的帮助文档里也有完备的使用教程。在此仅举例说明其使用方法。我自己使用的是的插件,使用插件要比稍微方便一些。
使用进行内存分析需要几个步骤,包括:生成文件、打开并导入文件、使用的视图工具分析内存。以下详细介绍。
(一) 生成.hprof文件
生成文件的方法有很多,而且的不同版本中生成的方式也稍有差别,我使用的版本的是,各个版本中生成文件的方法请参考:
http://android.git.kernel.org/?p=platform/dalvik.a=blob_f=docs/heap-profiling.hb=HEAD。
1. 打开并切换到透视图,同时确认、和视图已经打开了;
2. 将手机设备链接到电脑,并确保使用“调试”模式链接,而不是““模式;
3. 链接成功后在视图中就会看到设备的序列号,和设备中正在运行的部分进程;
4. 点击选中想要分析的应用的进程,在视图上方的一行图标按钮中,同时选中“”和“”两个按钮;
5. 这是工具将会自动生成当前选中进程的文件,并将其进行转换后存放在当中,如果你已经安装了插件,那么此时将会自动被启用,并开始对文件进行分析;
注意:第步和第步能够正常使用前提是我们需要有,并且当前进程有向中写入的权限,否则文件不会被生成,在中会显示诸如
ERROR/dalvikvm(8574): hprof: can't open /sdcard/com.xxx.hprof-hptemp: Permission denied.
如果我们没有,或者当前进程没有向写入的权限(如),那我们可以这样做:
6. 在当前程序中,例如中某些代码中,可以使用中的:
public static void dumpHprofData(String fileName) throws IOException
方法,手动的指定文件的生成位置。例如:
xxxButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
android.os.Debug.dumpHprofData("/data/temp/myapp.hprof");
上述代码意图是希望在被点击的时候开始抓取内存使用信息,并保存在我们指定的位置:,这样就没有权限的限制了,而且也无须用。但要保证目录是存在的。这个路径可以自己定义,当然也可以写成当中的某个路径。
(二) 使用MAT导入.hprof文件
1. 如果是自动生成的文件,可以使用插件直接打开(可能是比较新的才支持);
2. 如果自动生成的文件不能被直接打开,或者是使用方法手动生成的文件,则需要将文件进行转换,转换的方法:
例如我将文件拷贝到上的目录下,并输入命令,其中为原始文件,为转换过后的文件。转换过后的文件自动放在目录下。,到此为止,文件处理完毕,可以用来分析内存泄露情况了。
3. 在中点击,或者打的。在中点击,浏览并导入刚刚转换而得到的文件。
(三) 使用MAT的视图工具分析内存
导入文件以后,会自动解析并生成报告,点击,并按分组,选择自己所定义的类点右键,在弹出菜单中选择。这时会列出所有可疑类,右键点击某一项,并选择,会进一步筛选出跟程序相关的所有有内存泄露的类。据此,可以追踪到代码中的某一个产生泄露的类。
MAT的界面如下图所示。
具体的分析方法在此不做说明了,因为在的官方网站和客户端的帮助文档中有十分详尽的介绍。
了解中各个视图的作用很重要,例如中介绍的。
总之使用分析内存查找内存泄漏的根本思路,就是找到哪个类的对象的引用没有被释放,找到没有被释放的原因,也就可以很容易定位代码中的哪些片段的逻辑有问题了。
至此请各位自己动手,丰衣足食吧!
&!--EndFragment--&
浏览 27392
你好, 我在代码里加入了下面这句,但一直报错,未找到原因,请问是什么原因,谢谢!建议检查一下log,“check log output for details”,log中是否直接输出了原因。应该是说你没权限。1. 检查一下你的应用是否申请了SD卡的写权限2. 换个目录输出,比如:/sdcard/temp/dump.hprof
浏览: 347613 次
来自: 北京
summertime2013 写道最后一句话,为什么继续超过1 ...
真心牛人啊
最后一句话,为什么继续超过10秒没返回,又会引起第2种ANR? ...
楼主,求出书啊。求内容啊
读了您的几篇文章,找到了很多昨天上午向您请教问题的答案,受益匪 ...
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 android内存泄漏工具 的文章

 

随机推荐