Android上使用leaktracer的经验分享

前言

上周使用了LeakTracer来分析我们项目的SDK的内存问题,最终的成效还算可以。工具能正常使用,通过内存泄漏日志文件中的函数调用堆栈,结合查看源代码找到不少的内存使用不当的问题。我的使用场景是:

  1. 在初始化SDK前调用 leaktracer::MemoryTrace::GetInstance().startMonitoringAllThreads(),启动内存监控。
  2. 在销毁SDK后再调用leaktracer::MemoryTrace::GetInstance().writeLeaksToFile("/sdcard/rt_leak.log") ,结束内存监控,并输出日志文件
  3. 通过日志文件case by case的分析问题

几条干货

跟大家分享下如几点

  • 官网的源码收集到的函数地址是进程地址空间的绝对地址,不利于后面的函数符号的解析,这里推荐使用这个哥们优化后的源码 AndroidLeakTracer,主要优化点是,使用dladdr来做地址的转换(绝对地址换成so中的相对地址),有了相对地址,使用add2line工具还有有符号信息的so就能解析出具体的函数调用堆栈点的函数名,还有源文件的行号等信息了
  • 接入方式的话我是直接采用了源码的接入方式,把leaktracer源码放在我们SDK工程下跟SDK的源码一起编译并生成so,然后在AS的demo module去使用SDK的so 。有尝试过在demo module的jni层接入,即在demo 的cpp目录下放leaktracer的源码并构建,但始终收集到的日志解析出来的函数调用栈的符号解析不正常!(这个后期有时间需要研究下)
  • LeakTracer项目提供的日志文件的解析脚本 leak-analyze-addr2line(perl脚本) 中有使用到add2line命令行工具,所以需要我们的bash环境有add2line的配置,需要特别注意:通过alias配置add2line的路径,perl的运行环境是访问不到的。所以我的解决方案是修改leak-analyze-addr2line脚本,增加第三个参数,指定add2line的实际路径
    在这里插入图片描述
  • 建议还是直接使用addr2line一个case by case的去分析泄漏点的函数调用堆栈,可以考虑先分析内存泄漏比较严重中的case,于size的值为权重。
  • c++的类的虚构方法会自动的帮忙我们调用非指针类型的成员变量的虚构方法,帮忙我们回收成员变量的内存,但指针类型的成员变量是不会帮忙我们处理的。所以要特别关注指针类型的成员变量,一般内存泄漏多数是指针类型的成员变量引发。还有就是写代码的时候,特别要注意==nullptr与!=nullptr的判断,这种不小心的“低级”错误下,往往会伴随内存泄漏(判断条件写错了,没有调到delete 变量)。
  • 建议把leaktracer相关接口的调用再做一层封装,把接口的调用放到子线程中,这个在Android环境上更为重点与急切,避免ANR的出现
  • 需要处理申请应用读写文件的读取权限,否侧日志写入会失败!

PS: 本文对应的开发环境是 masOS Mojava 10.14.5

日志文件

日志文件的内容长如下样子
在这里插入图片描述
TIPS: 日志文件可以保存为cvs后缀,然后可以用WPS或osx上的Numbers表格打开,这样的话可以多维度或聚合性的去分析case,提高工作效率
在这里插入图片描述

add2line的使用

示例如下,这里使用addr2line工具解析数据调用堆栈,下面是使用llvm-addr2line的示例(macOS)

# llvm-addr2line is hashed (/Users/dw_luogongwu/Library/Android/sdk/ndk/21.2.6472646/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-addr2line)
# llvm-addr2line -p -f -C -e so文件路径 函数地址(多个值,从leak.log的一行记录的stack值)

在这里插入图片描述

接入参考

如下是我们SDK的接入的情况,供大家参考
PS: 当前SDK是采用CMake来构建的

  1. 把leaktracer丢在工程cpp代码的根目录下
    在这里插入图片描述
    1.在CMakeLists.txt文件添加,leaktracer的编译配置
    加头文件
    在这里插入图片描述
    加cpp路径
    在这里插入图片描述

leaktracer的接入方式

引用自使用LeakTracer检测android NDK C/C++代码中的memory leak

可以以3种方式来使用使用LeakTracer:

  1. 将自己的程序与libleaktracer.a进行链接,也就是将自己的程序一个静态链接库libleaktracer.a进行链接,我们知道静态链接是会将库的代码揉进我们自己项目的目标代码so中的。
  2. 将自己的程序与libleaktracer.so进行链接。需要将-lleaktracer选项做为链接命令的第一个选项。当对程序执行"objdump -p"时,应该能看到leaktracer.so是Dynamic Section的第一个NEEDED entry才对。
  3. 通过LD_PRELOAD环境变量来使得libleaktracer.so在任何其它动态链接库之前被加载,然后不需要对程序做任何的更改,还可以通过环境变量来对LeakTracer的行为进行定制。

手机SD卡访问权限的获取

  1. 在应用的AndroidManifest.xml加上
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

1.在应用的Activity的Oncreate方法的最后加上如下代码

  if (Build.VERSION.SDK_INT >= 23) {
            int requestCodeContact = 101;
            String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            //验证是否许可权限
            for (String str : permissions) {
                if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    this.requestPermissions(permissions, requestCodeContact);
                    return;
                }
            }
        }

参考文档

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值