Android开发中的APP内存泄漏检测

本文详细介绍如何使用Android Studio及第三方工具检查Android应用的内存使用情况,并通过实例演示如何定位和解决内存泄漏问题。

使用android shell命令查看内存使用情况

使用adb shell dumpsys meminfo pkgname或者直接使用AndroidStudio里面的memory usage功能然后就会出现如下信息:

Applications Memory Usage (kB):
Uptime: 14237237 Realtime: 23790474

** MEMINFO in pid 8071 [com.xtc.watch] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap        0        0        0        0    21924     8558     6405
  Dalvik Heap   122472   122372        0    15672   143308    65400    77908
 Dalvik Other    10361    10076      164      224
        Stack      440      440        0        8
    Other dev        4        0        4        0
     .so mmap     6441     3452     2636     2048
    .apk mmap      611        0      340        0
    .ttf mmap      538        0      504        0
    .dex mmap     8407     1640     2940       40
   Other mmap       80        4        0        0
      Unknown    10940    10936        0      148
        TOTAL   160294   148920     6588    18140   165232    73958    84313

 Objects
               Views:      288         ViewRootImpl:        2
         AppContexts:       11           Activities:        2
              Assets:        5        AssetManagers:        5
       Local Binders:       30        Proxy Binders:       38
    Death Recipients:        3
     OpenSSL Sockets:        1

 SQL
         MEMORY_USED:      138
  PAGECACHE_OVERFLOW:       24          MALLOC_SIZE:       62

 DATABASES
      pgsz     dbsz   Lookaside(b)          cache  Dbname
         4       20            306       25/47/12  /data/data/com.xtc.watch/databases/upload.db
  • Native Heap是native层的内存堆栈,Dalvik Heap是java层的内存堆栈,如果这二者加起来的内存占用超过了应用最大内存限制就会报OOM异常,剩下的.so mmap是 C 库代码占用的内存,.jar mmap是Java 文件代码占用的内存 ,.apk mmap是apk代码占用的内存,.dex mmap是Dex 文件代码占用的内存
  • Objects中的Activities表示当前内存中的activity对象的个数,启动一个activity就会生成一个activity对象,当退出activity的时候,activity对象就会被释放,所以反复的进出一个activity界面然后查看Activities的个数有没有保持不变,如果增加了,那么就说明这个activity对象没有被释放,也就是说可能存在内存泄漏,但是具体哪里泄漏了并不知道

DDMS查看内存使用情况

eclipse中有一个ddms工具,可以查看线程信息(Threads),内存使用情况(VM Heap),内存分配跟踪(Allocation Tracker),CUP使用情况(Sysinfo CUP load),内存使用饼状图(Sysinfo Memory usage),这里我们暂时用到VM Heap,选择要查看的app进程,点击左上角的show heap updates,选择VM Heap并点击Cause GC按钮,然后就出现下图:
这里写图片描述
观察data object的Total Size选项,这个是app的创建的java对象做占用的内存大小,Count是总内存的对象的个数,反复的进出一个activity,看data object的Total Size有没有明显的增加,正常情况下进入一个activity的时候会明显增加,退出一个activity会有明显的回落,总体是维持在一个比较稳定的水平如果反复进出activity,Total Size不断上升,那么可能就存在内存泄漏了,需要具体排查

MAT分析内存泄漏,用AndroidStudio的Monitors的Memory

  • 多点击几下Initiate GC来回收一下可被释放的java对象,因为java的GC是定期有条件执行的,当内存中只存在很少的无用对象,这时候可能并不会触发GC,所以手动触发GC来保证开始检测内存的时候内存都是最干净的
  • 点击Dump Java Heap,然后过一会儿就会出现一份数据分析文件,这时候的这份数据文件是刚开始的程序对象内存占用情况,接下去就针对一个activity反复操作进出等等各种反复操作,觉得差不多了,这时候就再次疯狂点击Initiate GC回收一下可是放的对象,点击Dump Java Heap,这时候生成的数据分析文件就是经过你疯狂操作后的内存占用情况了
    这里写图片描述
    生成的上述两个文件右键,点击Export to Standar .hprof导出到一个自己指定的目录文件夹
  • 去官网上面下载MAT来打开这两个文件开始内存分析
    这里写图片描述
    上图中Problem Suspect部分是代表可能存在内存泄漏的地方,Remainder表示正常的部分,再继续往下看
    这里写图片描述
    这里写图片描述
    上面就是对可能存在内存泄漏部分的代码的一个详细的信息,可以看到有些byte数组占用了大量的内存,keywords也是byte[],第二张图的DexCache可能占用的较多的内存,再点击这里写图片描述红色部分就会出现一些对象的信息列表:
    这里写图片描述
    可以输入正则表达式来筛选你想要的类,包名下所有的类,Objects是对象的个数,Shallow Heap是当前对象所占用的内存大小,不包括对象内包含的对象的大小,Retained Heap表示当前对象包括对象内的子对象一共占用的内存大小,所以Retained Heap会比Shallow Heap大得多,对于一些我们已知的对象在内存不泄露的情况下,该对象的个数是确定的,所以可以通过分析Objects的个数来确定对象是否存在内存泄漏,例如同一个Activity对象在反复进出该Activity5次之后Objects的值为5,那就有问题了,说明同一个Activity创建了5个对象,正常情况下应该是退出Activity后,对象会被回收的,所以Objects的值应该是0才对,而有些对象的Objects不为0并不代表一定存在内存泄漏,例如ConnectionService是一个常驻的Service,那么它是不会被GC的,而ConnectionService里面的对象可不会被回收,所以这些对象的Objects值不为0其实就是正常的了,至于Shallow Heap和Retained Heap,我觉得可以用来分析一些对象的内存占用,Shallow Heap一般情况下不会很大,当你发现Retained Heap非常大的时候,那就说明该对象里面的对象可能占用了大量的内存,可能存在问题;在用Objects找到可能存在内存泄漏的对象后,右键List Objects,然后有两个选项:with outgoing references(表示的是当前对象,引用了外部引用)和with incoming references(表示的是当前查看的对象,被外部引用),一般当前对象泄漏了就是对象还被外部对象持有引用,无法被释放,所以我们选择查看with incoming references这里写图片描述,点击with incoming references后
    这里写图片描述
    可以看到TaskExecutor对象被外部的两个对象所引用到了,并且可以看到引用的路径,右键TaskExecutor,选择Path to GC Roots或者或者Merge Shortest Paths to GC Roots选项,再选择exclude all phantom/weak/soft .ect references排除所有的弱引用,软引用对象寻找看有没有存在GC Roots,如果没有那就说明这个对象不存在内存泄漏,最终是会被GC回收,如果存在GC Roots
    这里写图片描述
    在继续查看GC Roots的对象是什么,其实就是被哪一个对象所引用了,上图可以查看到被外部的sendTaskExecutor对象所引用了而sendTaskExecutor是在ConnectionService这个常驻Service中的,所以理论上是不应该被回收的,所以这里不算是内存泄漏,假如sendTaskExecutor是一个Activity里面的字段,而此时Activity已经退出了,那么这时候就属于内存泄漏了,因为Activity退出后,Activity资源包括里面的对象应该是被回收掉的,那就找到对应的代码去具体分析可能造成内存泄漏的问题所在了,这里明确一点,存在GC Roots的不一定就一定存在内存泄漏,GC是不会回收GC Root或者被GC Root所引用的对象的,java对象内存泄漏其实就是对象在不用的时候仍然被其他对象持有引用导致GC无法回收
  • 比较反复操作前的内存信息和反复操作后的内存信息分析前后有哪些不同这里写图片描述,点击红色部分后会出现下图
    这里写图片描述
    可以看到对比后的Objects和Shallow Heap信息,看Objects表示前后两种内存信息对于同一个对象是否有个数上的增加,因为如果对象能被正常回收,那么开始操作前是0,操作后经过GC应该也是0,如果个数增加了,那就表示这个对象可能存在内存泄漏了,拖动到底部可看到总的比较情况
    这里写图片描述
    上图可知,操作前的app的Objects总数比操作后的Objects少了1个,同时可以看到是HttpDns这个对象的问题,于是再切换到操作后的histogram去按照上述步骤查找GC Roots,再具体分析内存泄漏的问题
  • MAT当中还有一个dominator tree视图,具体就不复述了,可以参考这篇大神文章MAT内存分析

网上的开源项目LeakCanary也是分析内存泄漏的一种有效方法

03-26
### 逆向工程与反编译概述 逆向工程是一种通过对软件的目标代码进行分析,将其转化为更高级别的表示形式的过程。这一过程通常用于研究现有系统的内部结构、功能以及实现细节。在Java和Android领域,反编译工具被广泛应用于逆向工程中。 #### Java逆向工程中的Jad反编译工具 Jad是一款经典的Java反编译工具,能够将`.class`字节码文件转换为可读的`.java`源代码[^1]。虽然它可能无法完全恢复原始源代码,但它提供了足够的信息来帮助开发者理解已编译的Java程序逻辑。Jad支持多种反编译模式,并允许用户自定义规则以适应不同的需求。此外,其命令行接口和图形界面使得复杂代码的分析变得更加便捷。 #### Android逆向工程中的JEB反编译工具 针对Android应用的逆向工程,JEB是由PNF Software开发的一款专业级工具[^2]。相较于其他同类产品,JEB不仅具备强大的APK文件反编译能力,还能对Dalvik字节码执行高效而精准的操作。它的核心优势在于以下几个方面: - **广泛的平台兼容性**:除Android外,还支持ARM、MIPS等多种架构的二进制文件反汇编。 - **混淆代码解析**:内置模块能有效应对高度混淆的代码,提供分层重构机制以便于深入分析。 - **API集成支持**:允许通过编写Python或Java脚本来扩展功能并完成特定任务。 #### APK反编译流程及其意义 当涉及到具体的APK包时,可以通过一系列步骤提取其中的信息来进行全面的安全评估或者学习目的的研究工作[^3]。这些步骤一般包括但不限于获取资产目录(`assets`)内的资源数据;解密XML配置文档如`AndroidManifest.xml`定位应用程序启动点;最后利用上述提到的各种专用软件重现整个项目框架供进一步探讨。 ```bash # 使用apktool反编译APK示例 apktool d your_app.apk -o output_directory/ ``` 以上命令展示了如何借助开源工具ApkTool轻松拆卸目标安卓档案至易于探索的状态下。 ### 结论 无论是传统的桌面端还是现代移动端环境里头,恰当运用合适的反编译解决方案都是达成逆向工程项目成功不可或缺的一环。每种工具有各自专精之处,在实际应用场景当中应当依据具体需求做出明智的选择。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值