导航:首页 > 操作系统 > android测试内存泄露

android测试内存泄露

发布时间:2023-02-11 16:08:55

1. 如何用MAT分析android程序的内存泄露

1.TraceView 1)功能:用于热点分析和性能优化,分析每个函数占用的CPU时间,调用次数,函数调用关系等 2)方法: a)在程序代码中加入追踪开关 import android.os.Debug; …… android.os.Debug.startMethodTracing(“/data/tmp/test”);// 先建/data/tmp目录 ……// 被追踪的程序段 android.os.Debug.stopMethodTracing(); b)编译,运行后,设备端生成/data/tmp/test.trace文件 c)把trace文件复制到PC端 $ adb pull /data/tmp/test.trace ./ d)使用android自带工具分析trace文件 $ANDROID_SRC/out/host/linux-x86/bin/traceview test.trace 此时可看到各个函数被调用的次数CPU占用率等信息 e)使用android自带工具分析生成调用关系类图 $ apt-get install graphviz# 安装图片相关软件 $ANDROID_SRC/out/host/linux-x86/bin/dmtracemp -g test.png test.trace 此时目录下生成类图test.png 3)注意 trace文件生成与libdvm模块DEBUG版本相冲突,所以此方法只适用于对非DEBUG版本模拟器的调试,否则在分析trace文件时会报错 2.HProf (Heap Profile) 1)功能: 用于java层面的内存分析,显示详细的内存占用信息,指出可疑的内存泄漏对象 2)方法: a)在代码中加入mp动作 import android.os.Debug; import java.io.IOException; …… try { android.os.Debug.mphprofData(“/data/tmp/input.hprof”); // 先建/data/tmp目录 } catch (IOException ioe) { } b)把hprof文件复制到PC端 $ adb pull /data/tmp/input.hprof ./ c)使用命令hprof-conv把hprof转成MAT识别的标准的hprof $ $ANDROID_SRC/out/host/linux-x86/bin/hprof-conv input.hprof output.hprof d)使用MAT工具看hprof信息 下载MAT工具:/mat/downloads.php 用工具打开output.hprof 3)注意:此工具只能显示java层面的,而不能显示C层的内存占用信息 3.SamplingProfile (android 2.0上版本使用) 1)功能 每隔N毫秒对当前正在运行的函数取样,并输出到log中 2)在代码中加入取样设定 import dalvik.system.SamplingProfiler …… SamplingProfile sp = SamplingProfiler.getInstance(); sp.start(n);// n为设定每秒采样次数 sp.logSnapshot(sp.snapshot()); …… sp.shutDown(); 它会启一个线程监测,在logcat中打印信息 4.用发系统信号的方式取当前堆栈情况和内存信息 1)原理 dalvik虚拟机对SIGQUIT和SIGUSR1信号进行处理(dalvik/vm/SignalCatcher.c),分别完成取当前堆栈和取当前内存情况的功能 2)用法 a)$ chmod 777 /data/anr -R# 把anr目录权限设为可写 $ rm /data/anr/traces.txt# 删除之前的trace信息 $ ps # 找到进程号 $ kill -3 进程号 # 发送SIGQUIT信号给该进程,此时生成trace信息 $ cat /data/anr/traces.txt 功能实现:遍历thread list(dalvik/vm/Thread.c:dvmDumpAllThreadEx()),并打印当前函数调用关系(dalvik/vm/interp/Stack.c:mpFrames()) b)$ chmod 777 /data/misc -R $ ps # 找到进程号 $ kill -10 进程号 # 发送SIGQUIT信事信号给该进程,此时生成hprof信息 $ ls /data/misc/*.hprof 此时生成hprf文件,如何使用此文件,见第二部分(HProf) 注意:hprof文件都很大,注意用完马上删除,以免占满存储器 5.logcat及原理 1)android.util.Log利用println的标准java输出词句,并加前缀I/V/D…. 2)dalvik利用管道加线程的方式,先利用p2把stdout和stderr重定向到管理中(vm/StdioConverter.c:dvmstdioConverterStartup),然后再启动一个线程从管道另一端读出内容(dalvik/vm/StdioConverter.c:stdioconverterThreadSt art()),使用LOG公共工具(system/core/liblog/logd_write.c: __android_log_print())输出到/dev/log/*中去 3)logcat通过加不同参数看/dev/log/下的不同输入信息 # logcat -b main显示主缓冲区中的信息 # logcat -b radio显示无线缓冲区中的信息 # logcat -b events显示事件缓冲区中的信息 6.jdwp(java debug wire protocol)及原理 1)虚拟机(设备端)在启动时加载了Agent JDWP 从而具备了调试功能。在调试器端(PC端)通过JDWP协议与设备连接,通过发送命令来获取的状态和控制Java程序的执行。JDWP 是通过命令(command)和回复(reply)进行通信的。 2)JDK 中调试工具 jdb 就是一个调试器,DDMS也提供调试器与设备相连。 3)dalvik为JDWP提供了两种连接方式:tcp方式和adb方式,tcp方式可以手工指定端口,adb方式自动设定为8700端口,通常使用DDMS调试就是通过adb方式 7.monkey 1)monkey是一个android自带的命令行工具。它向系统发送伪随机的用户事件流,实现对正在开发的应用程序进行压力测试。 2)方法 在设备端打开setting界面 $ adb shell # monkey -p com.android.settings -v 500 此时可以看到界面不断被切换 8.其它小工具 具体见android.os.Debug中提供的工具 1)取毫微秒级的时间,用于计算时间 threadCpuTimeNanos() 2)统计两点间的内存分配情况 startAllocCounting() stopAllocCounting() getGlobalAllocCount() get….. 3)打印当前已load的class getLoadedClassCount() printLoadedClasses()它需要打开NDEBUG功能才能打开system/core/中Log功能 9.打印debug信息 $ adb bugreport

2. Android内存优化三:内存泄漏检测与监控

Android内存优化一:java垃圾回收机制
Android内存优化二:内存泄漏
Android内存优化三:内存泄漏检测与监控
Android内存优化四:OOM
Android内存优化五:Bitmap优化

Memory Profiler 是 Profiler 中的其中一个版块,Profiler 是 Android Studio 为我们提供的性能分析工具,使用 Profiler 能分析应用的 CPU、内存、网络以及电量的使用情况。

进入了 Memory Profiler 界面。

点击 Record 按钮后,Profiler 会为我们记录一段时间内的内存分配情况。

在内存分配面板中,通过拖动时间线来查看一段时间内的内存分配情况

通过搜索类或者报名的方式查看对象的使用情况

使用Memory Profiler 分析内存可以查看官网: 使用内存性能分析器查看应用的内存使用情况

对于内存泄漏问题,Memory Profiler 只能提供一个简单的分析,不能够确认具体发生问题的地方。

而 MAT 就可以帮我们做到这一点,它是一款功能强大的 Java 堆内存分析工具,可以用于查找内存泄漏以及查看内存消耗情况。

as 生成hprof文件无法被mat识别,需要进行转换

使用hprof-conv进行转换,hprof-conv位于sdkplatform-tools

ps:as导出hprof前最好先gc几次,可排除一些干扰

Histogram 可以列出内存中的对象,对象的个数以及大小; Dominator Tree 可以列出那个线程,以及线程下面的那些对象占用的空间; Top consumers 通过图形列出最大的object; Leak Suspects 通过MA自动分析泄漏的原因。

Shallow Heap就是对象本身占用内存的大小,不包含其引用的对象内存,实际分析中作用不大。常规对象(非数组)的ShallowSize由其成员变量的数量和类型决定。数组的shallow size有数组元素的类型(对象类型、基本类型)和数组长度决定。对象成员都是些引用,真正的内存都在堆上,看起来是一堆原生的byte[], char[], int[],对象本身的内存都很小。

Retained Heap值的计算方式是将Retained Set(当该对象被回收时那些将被GC回收的对象集合)中的所有对象大小叠加。或者说,因为X被释放,导致其它所有被释放对象(包括被递归释放的)所占的heap大小。

Path To GC Roots -> exclude all phantim/weak/soft etc. references:查看这个对象的GC Root,不包含虚、弱引用、软引用,剩下的就是强引用。从GC上说,除了强引用外,其他的引用在JVM需要的情况下是都可以 被GC掉的,如果一个对象始终无法被GC,就是因为强引用的存在,从而导致在GC的过程中一直得不到回收,因此就内存泄漏了。

List objects -> with incoming references:查看这个对象持有的外部对象引用

List objects -> with outcoming references:查看这个对象被哪些外部对象引用

使用对象查询语言可以快速定位发生泄漏的Activity及Fragment

使用 MAT 来分析内存问题,效率比较低,为了能迅速发现内存泄漏,Square 公司基于 MAT 开源了 LeakCanary ,LeakCanary 是一个内存泄漏检测框架。

集成LeakCanary后,可以在桌面看到 LeakCanary 用于分析内存泄漏的应用。

当发生泄漏,会为我们生成一个泄漏信息概览页,可以看到泄漏引用链的详情。

LeakCanary 会解析 hprof 文件,并且找出导致 GC 无法回收实例的引用链,这也就是泄漏踪迹(Leak Trace)。

泄漏踪迹也叫最短强引用路径,这个路径是 GC Roots 到实例的路径。

LeakCanary 存在几个问题,不同用于线上监控功能

线上监控需要做的,就是解决以上几个问题。

各大厂都有开发线上监控方案,比如快手的 KOOM ,美团的 Probe ,字节的 Liko

快手自研OOM解决方案KOOM今日宣布开源

总结一下几点:

通过无性能损耗的 内存阈值监控 来触发镜像采集。将对象是否泄漏的判断延迟到了解析时

利用系统内核COW( Copy-on-write ,写时复制)机制,每次mp内存镜像前先暂停虚拟机,然后fork子进程来执行mp操作,父进程在fork成功后立刻恢复虚拟机运行,整个过程对于父进程来讲总耗时只有几毫秒,对用户完全没有影响。

3. 如何使用MAT分析Android应用内存泄露

使用Android Studio,Android Device Monitor 配合Eclipse的MAT(

Memory Analyzer)工具来分析android内存泄露。

1、新建一个Android 测试应用。填写好应用的名称,以及保存位置后,直接下一步到最后点击“Finish”。

4. Android技术分享|Android 中部分内存泄漏示例及解决方案

内存泄漏:

举例:

请注意以下的例子是虚构的

内存抖动

源自Android文档中的 Memory churn 一词,中文翻译为内存抖动。

指快速频繁的创建对象从而产生的性能问题。

引用Android文档原文:

Java内存泄漏的根本原因是 长生命周期 的对象持有 短生命周期 对象的引用就很可能发生内存泄漏。

尽管短生命周期对象已经不再需要,但因为长生命周期依旧持有它的引用,故不能被回收而导致内存泄漏。

静态集合类引起的内存泄漏


如果仅仅释放引用本身(tO = null), ArrayList 依然在引用该对象,GC无法回收。

监听器

在Java应用中,通常会用到很多监听器,一般通过 addXXXXListener() 实现。但释放对象时通常会忘记删除监听器,从而增加内存泄漏的风险。

各种连接

如数据库连接、网络连接(Socket)和I/O连接。忘记显式调用 close() 方法引起的内存泄漏。

内部类和外部模块的引用

内部类的引用是很容易被遗忘的一种,一旦没有释放可能会导致一系列后续对象无法释放。此外还要小心外部模块不经意的引用,内部类是否提供相应的操作去除外部引用。

单例模式

由于单例的静态特性,使其生命周期与应用的生命周期一样长,一旦使用不恰当极易造成内存泄漏。如果单利持有外部引用,需要注意提供释放方式,否则当外部对象无法被正常回收时,会进而导致内存泄漏。

集合类泄漏

如集合的使用范围超过逻辑代码的范围,需要格外注意删除机制是否完善可靠。比如由静态属性 static 指向的集合。

单利泄漏

以下为简单逻辑代码,只为举例说明内存泄漏问题,不保证单利模式的可靠性。


AppManager 创建时需要传入一个 Context ,这个 Context 的生命周期长短至关重要。

1. 如果传入的是 Application 的 Context ,因为 Application 的生命周期等同于应用的生命周期,所以没有任何问题。

2. 如果传入的是 Activity 的 Context ,则需要考虑这个 Activity 是否在整个生命周期都不会被回收了,如果不是,则会造成内存泄漏。

非静态内部类创建静态实例造成的内存泄漏


应该将该内部类单独封装为一个单例来使用。

匿名内部类/异步线程


Runnable都使用了匿名内部类,将持有MyActivity的引用。如果任务在Activity销毁前未完成,将导致Activity的内存无法被回收,从而造成内存泄漏。

解决方法:将Runnable独立出来或使用静态内部类,可以避免因持有外部对象导致的内存泄漏。

Handler造成的内存泄漏


Handler属于TLS(Thread Local Storage)变量,生命周期与Activity是不一致的,容易导致持有的对象无法正确被释放

当Android应用程序启动时,该应用程序的主线程会自动创建一个Looper对象和与之关联的MessageQueue。

当主线程中实例化一个Handler对象后,它就会自动与主线程Looper的MessageQueue关联起来。所有发送到MessageQueue的Messag都会持有Handler的引用,所以Looper会据此回调Handle的handleMessage()方法来处理消息。只要MessageQueue中有未处理的Message,Looper就会不断的从中取出并交给Handler处理。

另外,主线程的Looper对象会伴随该应用程序的整个生命周期。

在Java中,非静态内部类和匿名类内部类都会潜在持有它们所属的外部类的引用,但是静态内部类却不会。

当该 Activity 被 finish() 掉时,延迟执行任务的 Message 还会继续存在于主线程中,它持有该 Activity 的 Handler 引用,所以此时 finish() 掉的 Activity 就不会被回收了从而造成内存泄漏(因 Handler 为非静态内部类,它会持有外部类的引用,在这里就是指 SampleActivity)。


避免不必要的静态成员变量

对于BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等资源的使用,应在Activity销毁前及时关闭或注销。

不使用WebView对象时,应调用`destroy()`方法销毁。

5. Android开发中,有哪些好方法可以检测内存泄露和性能

下面是回答的内容


内存泄露,是Android开发者最头疼的事。可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴。怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的Android Studio 检测内存非常方便, 如果结合上MAT工具,LeakCanary插件,一切就变得so easy了。


熟悉Android Studio界面工欲善其事,必先利其器。


我们接下来先来熟悉下Android Studio的界面

结果

非独占时间:某函数占用的CPU时间,包含内部调用其它函数的CPU时间。
独占时间:某函数占用CPU时间,但不含内部调用其它函数所占用的CPU时间。

我们如何判断可能有问题的方法?

通过方法的调用次数和独占时间来查看,通常判断方法是:

如果方法调用次数不多,但每次调用却需要花费很长的时间的函数,可能会有问题。

如果自身占用时间不长,但调用却非常频繁的函数也可能会有问题。

综述

上面给大家介绍了若干使用Android Studio检查程序性能的工具,工具永远是辅助,不要因为工具耽误太长时间。如果有问题,欢迎大家纠正。

6. 排查内存泄漏最简单和直观的方法

内存泄漏无疑会严重影响用户体验,一些本应该废弃的资源和对象无法被释放,导致手机内存的浪费,app使用的卡顿,那么如何排查内存泄漏呢?

当然,首先我门有google的官方文档可以参考:

大部分博客的方法也来自于此。总的来说,就是使用android studio 的monitor memory功能监测app主进程占用的内存,触发GC操作,而后观察内存的占用情况,如果在使用的过程中内存不断增加,没有回落, 很有可能 发生了内存泄漏,这时候就需要导出内存分配的具体详情进行深入分析了。

但是事实上,通过观察这个内存曲线的曾场来或者是观察allocate tracker中的allocate data数值的增长来检测是否有内存泄漏问题,真的很玄,因为往往内存泄漏发生了,但是GC仍然可以通过回收其他对象的方式腾出空间,导致这个数据的变化基本看不出来,甚至是减小的,所以我觉得这种方式, 就像是让你用手掌去感知婴儿的体温,去检测确定这个婴儿有没有发烧一样,非常不靠谱不准确。

那么,重点来了,我的方法,简单直观,保准你一学就会!

先说一个terminal指令: 

这条指令是用来查询这个进程所占用的内存的具体详情的,通过这条指令可以看到当前app在手机中占用的具体的堆内存大小,view的数量, activity的数量 ,等等。如下图:

其中activity数目是非常关键的一个信息,可以帮助我们快速地检测出内存泄漏。我们可以反复地进入退出需要测试的目标activity,如果在反复进入退出之后,用terminal执行上面的语句查询当前的内存情况,如果发现activity数量一直在增长,那么内存泄露一定是发生了!

内存泄漏已经发生,如何定位原因呢?

如下图,在android studio中开始memory monitor,点击init GC,反复进入退出发生了内存泄漏的activity,这时候点击生成内存文件,这之后android studio会自动打开生成的.hprof文件。选中该文件转化成标准的hrof文件。

用MAT工具打开生成的.hprof文件,点击如下所示的图标,可以看到内存中的对象列表。

考虑到大内存的泄漏都是因为Activity被destroy之后却仍然被其他对象持有而造成的,因此首先解决棘手问题,直接搜索Activity,如下。发现有Activity的实例个数是3,跟实际不符,明显这个activity导致内存泄漏了,按照如图的方式找到它的引用,也就是导致内存泄漏的幕后兇手!

可以看到这个例子中的内存泄漏是由一个HandlerThread引发的,那么找到这个问题的位置,在合适的地方(如ondestroy)将这个handler thread释放即可。

如下图所示: 在android studio中打开生成的hprof文件,在右侧边栏会出现的Analyzer Tasks工具,点击执行图标,即可出现检测分析的结果,得到哪些activity被泄漏了,这些被泄漏的activity被谁引用了。

可以看到内存泄漏由AsyncHandler引起,需要在activity生命周期结束的时候进行释放。

方法2不用安装MAT工具,更加便捷哦~

 有问题可以留言,谢谢您的阅读~~

7. 怎么分析android代码是否存在内存泄露

1、首先确定是否有内存泄露及哪个程序造成。
1.1、内存泄露已弹出out of memory对话框的情况。
这种情况很简单,直接看对话框就知道是哪个应用的问题了。然后再分析该应用是否是因为内存泄露造成的
out of memory对话框。
》中介绍的各种方法进行分析,确定是否有内存泄露以及是哪个进程造成的内存泄露。
2、生成hprof文件,用MAT进行分析。

成hprof文件可以在DDMS选中进程点击窗口左上角的mp hprof
file按钮来直接生成,也可以通过在程序加代码中来生成代码2:voidgenerateHprof(){String
packageName=getApplicationInfo().packageName;
StringhpFilePath=/data/data/+packageName+/input.hprof;try{//Debug.mpHprofData(/sdcard/input.hprof);Debug.
mpHprofData
(hpFilePath);}catch(IOException e) {//TODOAuto-generated catch block
e.printStackTrace();}}建议使用代码生成hprof,然后使用《
Android内存泄露利器(hprof篇)》中的工具自动提取多个hprof文件,然后用MAT进行比较分析。在MAT导入.hprof文件以后,
MAT会自动解析并生成报告,点击
Dominator Tree
,并按Package分组,选择自己所定义的Package类,比较各个类在不同时期的RetainedHeap
,找出可疑类,然后选择该类,点右键,选中
show retained Set项,参看Retained Heap
的详细信息,进一步找出嫌疑项。
3、在代码中查找内存泄露。
根据在MAT找到的内存泄露信息,参照《
Android内存泄漏简介
》进一步在内存中查找内存泄露的原因并解决。
另外如果代码很简单,可以直接参照《
Android内存泄漏简介
》在内存中查找内存泄露的原因并解决。

8. Android内存泄露检测(二)

依赖库即可,重点在分析工具和分析方法:

debugImplementation'com.squareup.leakcanary:leakcanary-android:2.8.1'

分析工具:MAT 、AndroidStudioProfiler 和 自带分析工具;

这里先看一下Leaking的状态(YES、NO、UNKNOWN),NO表示没泄露、YES表示出现泄漏、UNKNOW表示可能泄漏。

具体学习资料: 学习资料

首先了解下Android中最重要的四大内存指标的概念

我们主要使用USS和PSS来衡量进程的内存使用情况

mpsys meminfo命令展示的是系统整体内存情况,内存项按进程进行分类

查看单个进程的内存信息,命令如下

adb shell mpsys meminfo [pid | packageName]

Objects中Views、Activities、AppContexts的异常可以判断有内存泄露,比如刚退出应用,查看Activites是否为0,如果不为0,则有Activity没有销毁。

 具体用法直接参考大佬的资源即可,不赘述。

android studio 中Memory Profile的用法

接入LeakCanary,监控所有Activity和Fragment的释放,App所有功能跑一遍,观察是否有抓到内存泄露的地方,分析引用链找到并解决问题,如此反复,直到LeakCanary检查不到内存泄露。

adb shell mpsys meminfo命令查看退出界面后Objects的Views和Activities数目,特别是退出App后数目为否为0。

打开Android Studio Memory Profiler,反复打开关闭页面多次,点击GC,如果内存没有恢复到之前的数值,则可能发生了内存泄露。再点击Profiler的垃圾桶图标旁的heap mp按钮查看当面内存堆栈情况,按包名找到当前测试的Activity,如果存在多份实例,则很可能发生了内存泄露。

阅读全文

与android测试内存泄露相关的资料

热点内容
数控铣床编程简单数字 浏览:786
编程电缆如何重启 浏览:121
myqq命令行发消息 浏览:365
日产逍客怎么使用app升窗 浏览:503
安卓系统怎么快速删除微信内容 浏览:653
csharppython 浏览:409
程序员脖子按摩仪 浏览:562
小米桌面文件夹乱码怎么回事 浏览:858
点歌台app怎么连接 浏览:318
大学电脑编程学什么好 浏览:348
上哪里取消应用加密 浏览:172
电气控制与可编程控制器pdf 浏览:87
cad图纸不能跨文件夹粘贴 浏览:256
学生云服务器主机 浏览:889
单片机状态周期 浏览:622
lua中的android 浏览:443
加密贵还是植发贵 浏览:664
阳光压缩机继电器 浏览:971
修改阿里云服务器密码 浏览:817
lk4102加密芯片 浏览:588