Android Raphael使用(专治native 内存泄漏)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

1.前期准备

在项目根目录build.gradle中,添加仓库地址

allprojects {
    repositories {
        maven { url 'https://jitpack.io' }
    }
}

2.案例实践

构建一个新的Library Module其中build.gradle中添加依赖

dependencies {
    implementation 'com.github.bytedance:memory-leak-detector:0.2.1'
}

Raphael API使用

Raphael是有两种方式可以监控进程中native内存 其一是通过java代码来实现其二是通过adb shell 发送广播命令行来控制。

启动监控

// 监控指定的so
Raphael.start(
    Raphael.MAP64_MODE|Raphael.ALLOC_MODE|0x0F0000|1024,
    "/storage/emulated/0/raphael", // 需要申请读写sdcard权限
    null      
);

参数

  • 第一个参数 指定模式
  • 第二个参数 native内存文件存放的目录若是sdcard则需要申请权限
  • 第三个参数指定监控的so库。比如监控libxxx.so中内存,则传入 ".*libxxx\\.so$"; 若传入null 则监控进程中全部so库

等同于adb shell 命令行实现

## 监控整个进程RaphaelReceiver 组件所在的进程
## 0x0CF0400=Raphael.MAP64_MODE|Raphael.ALLOC_MODE|0x0F0000|1024
adb shell am broadcast -a com.bytedance.raphael.ACTION_START -f 0x01000000 --es configs 0xCF0400

打印内存

// 代码控制
Raphael.print();

等同于

## 本地广播
adb shell am broadcast -a com.bytedance.raphael.ACTION_PRINT -f 0x01000000

更多API详情请阅读Raphael API使用

实现思路

为了灵活使用建议使用两者配合使用首先通过java 代码方式 在Application中启动监控整个进程其次涉及业务场景后通过adb shell 来打印内存缓存到指定目录下。

代码实现

基于raphael api 简单封装下代码如下

public class RaphaelUtils {

    /**
     * 监听整个进程中全部的so库内存泄漏
     */
    public static void monitorAllNativeSo(){
        String regexSo=null;
        monitorNativeSo(regexSo);
    }

    /**
     * 监控指定的 so 库内存泄漏
     * @param regexSo
     */
    public static void monitorNativeSo(String regexSo){
        final  String spaceDir="/storage/emulated/0/raphael";
        monitorNativeSo(spaceDir,regexSo);
    }
    /**
     * 用于监听so内存泄漏存储到指定位置
     * 也可以通过adb shell 命令行来执行(灵活使用)
     * adb shell am broadcast -a com.bytedance.raphael.ACTION_START -f 0x01000000 --es configs 0xCF0400 --es regex ".*libXXX\\.so$"
     *
     *
     * @param spaceDir  记录泄漏的存放地址这里必须获取 读写权限。
     *                  比如"/storage/emulated/0/raphael"
     * @param regexSo  传入null 监听全部so库。
     */
    public static void monitorNativeSo(String spaceDir,String regexSo){

        // 监控整个进程
        Raphael.start(Raphael.MAP64_MODE|Raphael.ALLOC_MODE|0x0F0000|1024,
                spaceDir,
                regexSo
        );
    }

    /**
     * 打印内存泄漏的信息存储导致sdcard中
     *
     * 也可以通过adb shell 命令行来执行(灵活使用)
     * adb shell am broadcast -a com.bytedance.raphael.ACTION_PRINT -f 0x01000000
     */
    public static void printNativeLeak(){
        Raphael.print();
    }

    /**
     * 停止监听
     * 也可以通过adb shell 命令行来执行(灵活使用)
     * adb shell am broadcast -a com.bytedance.raphael.ACTION_STOP -f 0x01000000
     */
    public static void stopMonitor(){
        Raphael.stop();
    }
}

在Application中onCreate()指定监控so库

    public void onCreate() {
        super.onCreate();
        RaphaelUtils.monitorNativeSo(    ".*libAppPlayx\\.so$");
    }

构建apk 进行安装启动后赋予读写权限进行一些列的业务操作进行adb shell 命令操作打印内存情况

adb shell am broadcast -a com.bytedance.raphael.ACTION_PRINT -f 0x01000000

内存文件将缓存在Raphael.start()中第二个传入的目录下这里是"/storage/emulated/0/raphael"

在这里插入图片描述

将其拷贝出来通过adb pull 也来拷贝。

配置Python 环境

report 文件是无法直接进行获取native 堆栈信息需要借用raphael.py 进行转换。先配置python的环境在官网下载python 3.x ,进行默认安装。

在命令中执行python 检查是否安装成功

在这里插入图片描述

为了方便将需要的几个文件都拷贝到同一个目录中

  • so对应addr2line工具
  • 带有符号表的so库
  • report文件
  • py脚本(raphael.py/mmap.py)

执行命令行如下若是report 过大执行会过长
在这里插入图片描述
执行完后会在同个目录中生成leak-doublets.txt里面包含内存信息和堆栈信息。
在这里插入图片描述

打开默认生成leak-doublets.txt:

  204,364,751	totals // 单指raphael拦截到的未释放的虚拟内存总和
  204,364,751	libAppPlayJNI.so  //该库未释放的内存

0x0000007865600000, 58741400, 1 
0x0000000001171d4c /data/app/~~vZjWn3Y0HAlsqNnxySQWjg==/com.xxx.miniworld-J6zXyou6Nnd_y7pG4EZo7g==/lib/arm64/libAppxxxJNI.so (F:/minichina/miniad/xxxx/OgreSingleton.h:110)
....

信息解读

内存和调用次数

0x0000007865600000, 58741400, 1  

0x0000007865600000是report里此堆栈第一次分配出的内存地址58741400是report里此堆栈的内存总和 1是report里此堆栈的总次数

native的调用栈

0x0000000001171d4c /data/app/~~vZjWn3Y0HAlsqNnxySQWjg==/com.xxx.miniworld-J6zXyou6Nnd_y7pG4EZo7g==/lib/arm64/libAppxxxJNI.so (F:/minichina/miniad/xxxx/OgreSingleton.h:110)

根据以上信息就很好分析哪些native 对象占用内存在某些业务场景下该进行释放。

3.借鉴

在这里插入图片描述

在这里插入图片描述

raphael其中有一个很好的借鉴方面通过adb shell 命令行发送广播命令从而执行一些逻辑操作。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: android