
大家好,我是 shixin。
在日常工作中,我們往往只關注 Java 內存使用情況,這主要是因為 Java 內存分析相關的工具比較多。與之不同的是,圖片內存分析的工具比較少,當分析圖片內存問題時我們需要花費很大的精力。
我們知道,在 Android 應用使用的內存中,圖片總是占據不少比例。拿小米 12 來說,3200 x 1440 的分辨率,一張全屏的圖片至少要占用 17MB(3200 x 1440 x 4 )。如果緩存里多幾張,基本就要達到上百 MB。加載的圖片稍有不當,就可能導致應用的內存溢出崩潰大大增加。
因此,我們需要這樣的工具:可以快速發(fā)現(xiàn)應用內加載的圖片是否合理,比如大小是否合適、是否存在泄漏、緩存是否及時清理、是否加載了當前并不需要的圖片等等。
AndroidBitmapMonitor 正是為此而生!它是一個開源的 Android 圖片內存分析工具,可以幫助開發(fā)者快速發(fā)現(xiàn)應用的圖片使用是否合理,支持在線下和線上使用。
AndroidBitmapMonitor 提供了這些功能:
- 獲取內存中的 Bitmap 數(shù)量及占用內存
- 查看 Bitmap 創(chuàng)建堆棧及線程
- 導出 Bitmap 圖片,幫助直接定位問題所屬業(yè)務
- 動態(tài)開關,可以在任意時間開始和結束
功能介紹
- 支持 Android 4.4 - 13 (API level 19 - 33)
- 支持 armeabi-v7a 和 arm64-v8a
- 支持線下實時查看圖片內存情況 和 線上數(shù)據統(tǒng)計
可以提供的功能:
- 獲取內存中的圖片數(shù)量及占用內存
- 獲取 Bitmap 創(chuàng)建堆棧及線程
- 全版本 Bitmap Preview,在堆棧無法看出問題時,可以用來定位圖片所屬業(yè)務
動圖:

核心功能截圖:
懸浮窗中可以實時查看到圖片內存

內存中的圖片信息

某張圖片的具體信息
使用文檔
主要有四步:
- 添加 gradle 依賴
- 初始化配置
- 在需要的時候調用 start 和 stop
- 獲取數(shù)據
1. 在 build.gradle 中增加依賴
Android Bitmap Monitor 發(fā)布在 mavenCentral 上,因此首先需要確保您的項目有使用 mavenCentral 作為倉庫。
您可以在根目錄的 build.gradle 或者 setting.gradle 中添加以下代碼:
allprojects {
repositories {
//...
//添加 mavenCentral 依賴
mavenCentral()
}
}
復制代碼
接著在具體業(yè)務的 build.gradle 文件中添加依賴:
android {
packagingOptions {
pickFirst 'lib/*/libshadowhook.so'
}
}
dependencies {
implementation 'io.github.shixinzhang:android-bitmap-monitor:1.0.2'
}
復制代碼
請注意:為了避免和其他庫沖突,上面的 packagingOptions 中
pickFirst 'lib/*/libshadowhook.so'是必要的。
添加完依賴并執(zhí)行 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) //獲取堆棧的閾值,當一張圖片占據的內存超過這個數(shù)值后就會去抓棧
.restoreImageThreshold(restoreImageThreshold) //還原圖片的閾值,當一張圖占據的內存超過這個數(shù)值后,就會還原出一張原始圖片
.restoreImageDirectory(dir) //保存還原后圖片的目錄
.showFloatWindow(true) //是否展示懸浮窗,可實時查看內存大?。ńㄗh只在 debug 環(huán)境打開)
.isDebug(true)
.context(this)
.build();
BitmapMonitor.init(config);
復制代碼
當 showFloatWindow 為 true 時,首次啟動 app 需要授予懸浮窗權限。
3. 開啟和停止監(jiān)控
初始化完成后,可以在任意時刻調用 start/stop 開啟和停止監(jiān)控:
//開啟監(jiān)控,方式1
BitmapMonitor.start();
//開啟方式2,提供頁面獲取接口,建議使用
BitmapMonitor.start(new BitmapMonitor.CurrentSceneProvider() {
@Override
public String getCurrentScene() {
//返回當前頂部頁面名稱
if (sCurrentActivity != null) {
return sCurrentActivity.getClass().getSimpleName();
}
return null;
}
});
//停止監(jiān)控
BitmapMonitor.stop();
復制代碼
上面的代碼中,開啟方式 2 的參數(shù)用來獲取圖片創(chuàng)建時的頁面名稱,這個接口可以幫助知道大圖是在哪個頁面創(chuàng)建的。如果不想提供這個接口可以使用開啟方式 1。
那我們該在什么使用開啟監(jiān)控呢?
一般有「全局開啟」和「分業(yè)務開啟」兩種使用方式:
- 全局開啟:一啟動就 start,用于了解整個 APP 使用過程中的圖片內存數(shù)據
- 分業(yè)務開啟:在進入某個業(yè)務前 start,退出后 stop,用于了解特定業(yè)務的圖片內存數(shù)據
4. 獲取數(shù)據
在初始化完成并開啟監(jiān)控后,我們就可以攔截到每張圖片的創(chuàng)建過程。
Android Bitmap Monitor 提供了兩種獲取內存中圖片數(shù)據的 API:
- 定時回調 addListener
- 主動獲取數(shù)據 dumpBitmapInfo
定時回調 是指注冊一個 listener,這個接口的回調會按照一定時間間隔被調用,可以用來做實時監(jiān)控:
BitmapMonitor.addListener(new BitmapMonitor.BitmapInfoListener() {
@Override
public void onBitmapInfoChanged(final BitmapMonitorData data) {
Log.d("bitmapmonitor", "onBitmapInfoChanged: " + data);
}
});
復制代碼
間隔時間是初始化時傳遞的參數(shù) checkRecycleInterval,返回的數(shù)據結構如下所示:
public class BitmapMonitorData {
//歷史創(chuàng)建的總圖片數(shù)
public long createBitmapCount;
//歷史創(chuàng)建的總圖片內存大小,單位 byte
public long createBitmapMemorySize;
//當前內存中還未回收的圖片數(shù)
public long remainBitmapCount;
//當前內存中還未回收的圖片內存大小,單位 byte
public long remainBitmapMemorySize;
//泄漏(未釋放)的 bitmap 數(shù)據
public BitmapRecord[] remainBitmapRecords;
//...
}
復制代碼
主動獲取數(shù)據 是指主動調用 BitmapMonitor.dumpBitmapInfo() 獲取內存中的所有數(shù)據,可以用在內存升高時上報數(shù)據:
//獲取所有數(shù)據
BitmapMonitorData bitmapAllData = BitmapMonitor.dumpBitmapInfo();
Log.d("bitmapmonitor", "bitmapAllData: " + bitmapAllData);
//僅獲取數(shù)量和內存大小,不獲取具體圖片信息
BitmapMonitorData bitmapCountData = BitmapMonitor.dumpBitmapCount();
Log.d("bitmapmonitor", "bitmapCountData: " + bitmapCountData);
復制代碼
dumpBitmapInfo 會返回內存中所有圖片的信息,如果只想獲取到圖片的總數(shù)和內存總量,可以調用 dumpBitmapCount,速度更快更輕量。
總結
這篇文章介紹了最新開源的圖片內存分析工具 Android Bitmap Monitor 的功能與核心 API,可以看到,它提供了很多圖片的信息,我們可以用它干什么呢?
目前想到這些使用場景:
- 大圖報警: 一旦線上出現(xiàn)過大的圖片加載,可以上報一條日志,通知開發(fā)人員檢查
- 圖片泄漏監(jiān)控:在頁面退出后圖片內存沒有下降,可以看看是什么圖片泄漏了,哪里代碼導致的
- 重復加載圖片:相同的圖片多次 decode,沒有利用好內存緩存
通過這個庫我們可以對 APP 的圖片使用情況有更深的了解,也可以讓知識面更廣一點,以后面試聊到內存優(yōu)化時可以不用擔心只會講 Java 內存了哈哈!還在等什么,快來使用吧!
如果對你有幫助,歡迎點一個 star,感謝:https://github.com/shixinzhang/AndroidBitmapMonitor