自研的内存分析利器开源了!Android Bitmap Monitor 助你定位不合理的图片使用

image.png

大家好,我是 shixin。

在日常工作中,我们往往只关注 Java 内存使用情况,这主要是因为 Java 内存分析相关的工具比较多。与之不同的是,图片内存分析的工具比较少,当分析图片内存问题时我们需要花费很大的精力。

我们知道,在 Android 应用使用的内存中,图片总是占据不少比例。拿小米 12 来说,3200 x 1440 的分辨率,一张全屏的图片至少要占用 17MB(3200 x 1440 x 4 )。如果缓存里多几张,基本就要达到上百 MB。加载的图片稍有不当,就可能导致应用的内存溢出崩溃大大增加。

因此,我们需要这样的工具:可以快速发现应用内加载的图片是否合理,比如大小是否合适、是否存在泄漏、缓存是否及时清理、是否加载了当前并不需要的图片等等。

AndroidBitmapMonitor 正是为此而生!它是一个开源的 Android 图片内存分析工具,可以帮助开发者快速发现应用的图片使用是否合理,支持在线下和线上使用

AndroidBitmapMonitor 提供了这些功能:

  1. 获取内存中的 Bitmap 数量及占用内存
  2. 查看 Bitmap 创建堆栈及线程
  3. 导出 Bitmap 图片,帮助直接定位问题所属业务
  4. 动态开关,可以在任意时间开始和结束

功能介绍

  • 支持 Android 4.4 - 13 (API level 19 - 33)
  • 支持 armeabi-v7a 和 arm64-v8a
  • 支持线下实时查看图片内存情况 和 线上数据统计

可以提供的功能:

  1. 获取内存中的图片数量及占用内存
  2. 获取 Bitmap 创建堆栈及线程
  3. 全版本 Bitmap Preview,在堆栈无法看出问题时,可以用来定位图片所属业务

动图:

![capture_1.jpg](https://upload-images.jianshu.io/upload_images/1523592-776ad0367dccab2a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

核心功能截图:

悬浮窗中可以实时查看到图片内存

capture_2.jpg

内存中的图片信息

capture_4.jpg

某张图片的具体信息

使用文档

主要有四步:

  1. 添加 gradle 依赖
  2. 初始化配置
  3. 在需要的时候调用 start 和 stop
  4. 获取数据

1. 在 build.gradle 中增加依赖

Android Bitmap Monitor 发布在 mavenCentral 上,因此首先需要确保您的项目有使用 mavenCentral 作为仓库。

您可以在根目录的 build.gradle 或者 setting.gradle 中添加以下代码:

allprojects {
    repositories {
        //...
        //添加 mavenCentral 依赖
        mavenCentral()
    }
}
复制代码

接着在具体业务的 build.gradle 文件中添加依赖:

android {
    packagingOptions {
        pickFirst 'lib/*/libshadowhook.so'
    }
}

dependencies {
    implementation 'io.github.shixinzhang:android-bitmap-monitor:1.0.2'
}
复制代码

请注意:为了避免和其他库冲突,上面的 packagingOptions 中 pickFirst 'lib/*/libshadowhook.so' 是必要的。

添加完依赖并执行 gradle sync 后,下一步就是在代码里进行初始化和启动。

2. 初始化

初始化需要调用的 API 是 BitmapMonitor.init

        long checkInterval = 10;
        long threshold = 100 * 1024;
        long restoreImageThreshold = 100 * 1024;;
        String dir = this.getExternalFilesDir("bitmap_monitor").getAbsolutePath();

        BitmapMonitor.Config config = new BitmapMonitor.Config.Builder()
                .checkRecycleInterval(checkInterval)    //检查图片是否被回收的间隔,单位:秒 (建议不要太频繁,默认 5秒)
                .getStackThreshold(threshold)           //获取堆栈的阈值,当一张图片占据的内存超过这个数值后就会去抓栈
                .restoreImageThreshold(restoreImageThreshold)   //还原图片的阈值,当一张图占据的内存超过这个数值后,就会还原出一张原始图片
                .restoreImageDirectory(dir)             //保存还原后图片的目录
                .showFloatWindow(true)                  //是否展示悬浮窗,可实时查看内存大小(建议只在 debug 环境打开)
                .isDebug(true)
                .context(this)
                .build();
        BitmapMonitor.init(config);
复制代码

当 showFloatWindow 为 true 时,首次启动 app 需要授予悬浮窗权限。

3. 开启和停止监控

初始化完成后,可以在任意时刻调用 start/stop 开启和停止监控:

        //开启监控,方式1
        BitmapMonitor.start();

        //开启方式2,提供页面获取接口,建议使用
        BitmapMonitor.start(new BitmapMonitor.CurrentSceneProvider() {
            @Override
            public String getCurrentScene() {
                //返回当前顶部页面名称
                if (sCurrentActivity != null) {
                    return sCurrentActivity.getClass().getSimpleName();
                }
                return null;
            }
        });

        //停止监控
        BitmapMonitor.stop();
复制代码

上面的代码中,开启方式 2 的参数用来获取图片创建时的页面名称,这个接口可以帮助知道大图是在哪个页面创建的。如果不想提供这个接口可以使用开启方式 1。

那我们该在什么使用开启监控呢?

一般有「全局开启」和「分业务开启」两种使用方式:

  1. 全局开启:一启动就 start,用于了解整个 APP 使用过程中的图片内存数据
  2. 分业务开启:在进入某个业务前 start,退出后 stop,用于了解特定业务的图片内存数据

4. 获取数据

在初始化完成并开启监控后,我们就可以拦截到每张图片的创建过程。

Android Bitmap Monitor 提供了两种获取内存中图片数据的 API:

  1. 定时回调 addListener
  2. 主动获取数据 dumpBitmapInfo

定时回调 是指注册一个 listener,这个接口的回调会按照一定时间间隔被调用,可以用来做实时监控

        BitmapMonitor.addListener(new BitmapMonitor.BitmapInfoListener() {
            @Override
            public void onBitmapInfoChanged(final BitmapMonitorData data) {
                Log.d("bitmapmonitor", "onBitmapInfoChanged: " + data);
            }
        });
复制代码

间隔时间是初始化时传递的参数 checkRecycleInterval,返回的数据结构如下所示:

public class BitmapMonitorData {
    //历史创建的总图片数
    public long createBitmapCount;
    //历史创建的总图片内存大小,单位 byte
    public long createBitmapMemorySize;

    //当前内存中还未回收的图片数
    public long remainBitmapCount;
    //当前内存中还未回收的图片内存大小,单位 byte
    public long remainBitmapMemorySize;

    //泄漏(未释放)的 bitmap 数据
    public BitmapRecord[] remainBitmapRecords;

    //...
}
复制代码

主动获取数据 是指主动调用 BitmapMonitor.dumpBitmapInfo() 获取内存中的所有数据,可以用在内存升高时上报数据

        //获取所有数据
        BitmapMonitorData bitmapAllData = BitmapMonitor.dumpBitmapInfo();
        Log.d("bitmapmonitor", "bitmapAllData: " + bitmapAllData);

        //仅获取数量和内存大小,不获取具体图片信息
        BitmapMonitorData bitmapCountData = BitmapMonitor.dumpBitmapCount();
        Log.d("bitmapmonitor", "bitmapCountData: " + bitmapCountData);
复制代码

dumpBitmapInfo 会返回内存中所有图片的信息,如果只想获取到图片的总数和内存总量,可以调用 dumpBitmapCount,速度更快更轻量。

总结

这篇文章介绍了最新开源的图片内存分析工具 Android Bitmap Monitor 的功能与核心 API,可以看到,它提供了很多图片的信息,我们可以用它干什么呢?

目前想到这些使用场景:

  1. 大图报警: 一旦线上出现过大的图片加载,可以上报一条日志,通知开发人员检查
  2. 图片泄漏监控:在页面退出后图片内存没有下降,可以看看是什么图片泄漏了,哪里代码导致的
  3. 重复加载图片:相同的图片多次 decode,没有利用好内存缓存

通过这个库我们可以对 APP 的图片使用情况有更深的了解,也可以让知识面更广一点,以后面试聊到内存优化时可以不用担心只会讲 Java 内存了哈哈!还在等什么,快来使用吧!

如果对你有帮助,欢迎点一个 star,感谢:https://github.com/shixinzhang/AndroidBitmapMonitor

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容