Giter VIP home page Giter VIP logo

androidbitmapmonitor's Introduction

Android Bitmap Monitor is an Android image memory analysis tool that can help developers quickly find out whether the image usage of their apps is reasonable, supporting both offline and online usage.

中文介绍


In the memory usage of Android applications, images always occupy a large proportion.

Take Xiaomi 12 (3200 x 1440 resolution) for example, a full screen image will take at least 17MB (3200 x 1440 x 4). If there are a few more in the cache, it will basically reach hundreds of MB, and the slightest impropriety may lead to a significant increase in memory overflow crashes of the application.

Therefore, we need a tool that can quickly find out whether the images loaded in the application are reasonable, such as whether the size is appropriate, whether there are leaks, whether the cache is cleaned in time, whether the images that are not currently needed are loaded, and so on.

AndroidBitmapMonitor is made for this purpose!

Update log

Version Changes Notes
1.1.0 Support clearing locally saved image data to avoid taking up too much storage Recommend
1.0.9 Optimize performance, reduce main thread time consumption
1.0.8 Fix the problem that images loaded with Glide may be solid black when restored; support no-op dependency (thanks to yibaoshan)
1.0.7 Improve the function of hover window and picture list, fix the problem that the hover window may appear more than one

Features

  1. Support Android 4.4 - 13 (API level 19 - 33)
  2. Support armeabi-v7a and arm64-v8a
  3. Support offline real-time image memory view and online statistics

Functions:

  1. Get the number of images in memory and how much memory they occupy
  2. Get Bitmap creation stacks and threads
  3. Bitmap Preview, which can be used to locate the business to which the image belongs when the stack cannot see the problem

Screenshot of core functionality:

Real-time view of image memory in the hover window

Image information in memory

Specific information about a particular image

Documentation

Use AndroidBitmapMonitor, there are four main steps:

  1. Adding gradle dependencies
  2. Initialize the configuration
  3. Call start and stop when needed
  4. Get the data

1.Adding dependencies in build.gradle

Android Bitmap Monitor is published on mavenCentral, so first you need to make sure your project uses mavenCentral as a repository.

You can add the following code to build.gradle or setting.gradle in the root directory.

allprojects {
	repositories {
		//...
		//add mavenCentral dependencies
		mavenCentral()
	}
}

Next, add the dependency to the business-specific build.gradle file.

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

dependencies {
   //dependencies 1, if you want to use it both online and offline, you can depend on it in the following way
   implementation 'io.github.shixinzhang:android-bitmap-monitor:1.1.0'

    // Dependency 2, if you don't want to have code running in the official package, you can depend on it in the following way
    releaseImplementation 'io.github.shixinzhang:android-bitmap-monitor-no-op:1.1.0'
    debugImplementation 'io.github.shixinzhang:android-bitmap-monitor:1.1.0'
}

Choose one of dependency 1 or 2.

Note: To avoid conflicts with other libraries, pickFirst 'lib/*/libshadowhook.so' in the packagingOptions above is necessary.

After adding the dependencies and executing gradle sync, the next step is to initialize and start it in the code.

2. Initialization

The API to be called for initialization is 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.
                .checkRecycleInterval(checkInterval)                            // check if the image is recycled interval, in seconds (recommended not too often, default 5 seconds)
                .getStackThreshold(threshold)                                   // get the threshold of the stack, when an image occupies more than this value of memory will go to grab the stack
                .restoreImageThreshold(restoreImageThreshold)                   // restore the image threshold, when a picture occupies more memory than this value, it will restore an original picture
                .restoreImageDirectory(dir)                                     // the directory of the restored image
                .showFloatWindow(true)                                          // whether to show a hover window to see the memory size in real time (recommended to open only in debug environment)
                .clearAllFileWhenRestartApp(true)                               
                .clearFileWhenOutOfThreshold(true)                              
                .diskCacheLimitBytes(100 * 1024 * 1024)                          
                .isDebug(true)
                .context(this)
                .build();
        BitmapMonitor.init(config);

When showFloatWindow is true, you need to grant hover window permission when you start the app for the first time.

3. Turning on and off monitoring

After initialization, you can call start/stop at any time to start and stop monitoring:

        //start monitoring, method 1
        BitmapMonitor.start();
        
        //Start way 2, provide page to get interface, recommended to use
        BitmapMonitor.start(new BitmapMonitor.CurrentSceneProvider() {
            @Override
            public String getCurrentScene() {
                //return the current top page name
                if (sCurrentActivity ! = null) {
                    return sCurrentActivity.getClass().getSimpleName();
                }
                return null;
            }
        });
        
        //Stop monitoring
        BitmapMonitor.stop();

In the above code, the parameter of open method 2 is used to get the page name when the image was created, this interface can help to know in which page the large image was created. If you don't want to provide this interface, you can use open method 1.

So what do we use to turn on monitoring?

Generally there are two ways to use "global start" and "business start".

  1. Global start: start as soon as app start, for understanding the image memory data during the whole APP usage
  2. Business start: start when you want, which is used to understand the image memory data of special business

4. Get data

After initialization and monitoring, we can intercept the creation process of each image.

Android Bitmap Monitor provides two APIs to get the image data in memory.

  1. Interval callback addListener
  2. Manual fetch data use dumpBitmapInfo

Interval callbacks means registering a listener, which will be called at certain intervals and can be used for real-time monitoring.

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

The interval is the parameter checkRecycleInterval passed during initialization, and the returned data structure is shown below:

public class BitmapMonitorData {
// history of the total number of images created
public long createBitmapCount;
// history of the creation of the total image memory size, unit byte
public long createBitmapMemorySize;

    // the current number of images in memory that have not been recycled
    public long remainBitmapCount;
    // the current memory has not been recycled image memory size, unit byte
    public long remainBitmapMemorySize;

    //leakage (not released) of bitmap data
    public BitmapRecord[] remainBitmapRecords;
    
    //...
}

Manual fetch data use dumpBitmapInfo, means actively calling BitmapMonitor.dumpBitmapInfo() to fetch all data in memory, which can be used to report data when memory is elevated.

        // Get all the data
        BitmapMonitorData bitmapAllData = BitmapMonitor.dumpBitmapInfo();
        Log.d("bitmapmonitor", "bitmapAllData: " + bitmapAllData);
        
        //get only the number and memory size, not the specific image information
        BitmapMonitorData bitmapCountData = BitmapMonitor.dumpBitmapCount();
        Log.d("bitmapmonitor", "bitmapCountData: " + bitmapCountData);

If you just want to get the total number of images and the total amount of memory, you can call dumpBitmapCount, which is faster and lighter.

Here we understand the core API of Android Bitmap Monitor, through this library we can have a deeper understanding of APP's image usage, and also make the knowledge a little wider! Come and use it!

Contributed by

  1. shixinzhang
  2. yibaoshan

Thanks

  1. The function hook is implemented by the powerful android-inline-hook, thanks.
  2. The image export is based on Nian Sun's implementation.

Contact me

License

Android Bitmap Monitor is licensed under Apache 2.0.

androidbitmapmonitor's People

Contributors

awxy avatar folderv avatar linchangjian avatar shixinzhang avatar yibaoshan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

androidbitmapmonitor's Issues

期望添加debug依赖

大佬参考下leakcanary,期望开发期间能发现问题并修正,但是正式上线后不希望有代码编译运行到用户真实环境中。

查看图片的时候黑屏

接入SDK之后,点击进入图片捕获列表,点击其中的图片进行查看详情。绝大部分图片都是黑的,没有显示出来。

环境:
android 10,pixel3.
implementation "com.github.bumptech.glide:annotations:4.12.0"

screen_cap_20230222_155504

Android 5.0 下与 relinker 同时使用 出现 native crash

signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: JNI FindClass called with pending exception 'java.lang.NoSuchFieldError' thrown in java.lang.String java.lang.Runtime.nativeLoad(java.lang.String, java.lang.ClassLoader, java.lang.String):-2'

调用start时crash

版本1.1.0
手机 pixel 3XL
已开启悬浮窗权限

Caused by android.app.BackgroundServiceStartNotAllowedException
Not allowed to start service Intent { flg=0x10000000 cmp=com.hk.azal.live/top.shixinzhang.bitmapmonitor.ui.FloatWindowService }: app is in background uid UidRecord{8e253cc u0a217 TRNB idle change:uncached procs:0 seq(0,0,0)}

调用BitmapMonitor.start()直接抛Native Crash崩溃

堆栈如下

2023-07-26 14:16:29.428 13596-13596 libc com.test.bitmapmonitor A Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 13596 (.bitmapmonitor), pid 13596 (.bitmapmonitor)
2023-07-26 14:16:29.949 13846-13846 DEBUG pid-13846 A Cmdline: com.test.bitmapmonitor
2023-07-26 14:16:29.949 13846-13846 DEBUG pid-13846 A pid: 13596, tid: 13596, name: .bitmapmonitor >>> com.test.bitmapmonitor <<<
2023-07-26 14:16:29.949 13846-13846 DEBUG pid-13846 A #1 pc 000000000000c5c8 /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/lib/arm64/libshadowhook.so (shadowhook_get_prev_func+12) (BuildId: a5399f0d11c4ec1244543780f0a31f2d62857f74)
2023-07-26 14:16:29.949 13846-13846 DEBUG pid-13846 A #2 pc 0000000000015ea4 /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/lib/arm64/libbitmapmonitor.so (create_bitmap_proxy(_JNIEnv*, void*, int, _jbyteArray*, _jobject*, int)+84) (BuildId: 97cfffda4c5cd149ae932e86d1bde0a7a74def05)
2023-07-26 14:16:29.949 13846-13846 DEBUG pid-13846 A #101 pc 00000000002ef00c [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.949 13846-13846 DEBUG pid-13846 A #107 pc 00000000002ef6b0 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #110 pc 00000000001e51a6 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #116 pc 00000000001d829a [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #122 pc 00000000001ecaac [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #128 pc 00000000001bae64 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #134 pc 00000000001bb278 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #140 pc 00000000001bb44a [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #146 pc 00000000001b6e26 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #152 pc 00000000001b07f0 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #158 pc 00000000001afd06 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #164 pc 000000000034c918 [anon:dalvik-classes.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #170 pc 00000000001ee030 [anon:dalvik-classes12.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk!classes12.dex]
2023-07-26 14:16:29.950 13846-13846 DEBUG pid-13846 A #176 pc 00000000000e4e14 [anon:dalvik-classes3.dex extracted in memory from /data/app/~~lPYxXLZv8f1xO1wzNk9G8g==/com.test.bitmapmonitor-9YoIsvqFII-QxHf9xKU2GQ==/base.apk!classes3.dex]

你好请教个问题

_ZN7android6bitmap12createBitmapEP7_JNIEnvPNS_6BitmapEiP11_jbyteArrayP8_jobjecti 你好请教个问题 这个函数符号你是怎么获取的

(Bug)初始化偶现崩溃问题

implementation "io.github.shixinzhang:android-bitmap-monitor:1.1.0"

        val ctx = ContextUtils.getApplication()
        val cacheFile = File(ctx.cacheDir, "bitmap_monitor")
        if (!cacheFile.exists()) {
            cacheFile.mkdirs()
        }
        val config = BitmapMonitor.Config.Builder()
            // 检查图片是否被回收的间隔,单位:秒 (建议不要太频繁,默认 5秒)
            .checkRecycleInterval(10L)
            // 获取堆栈的阈值,当一张图片占据的内存超过这个数值后就会去抓栈
            .getStackThreshold(100 * 1024L)
            // 还原图片的阈值,当一张图占据的内存超过这个数值后,就会还原出一张原始图片
            .restoreImageThreshold(100 * 1024L)
            .restoreImageDirectory(cacheFile.absolutePath)
            // 是否展示悬浮窗,可实时查看内存大小(建议只在 debug 环境打开)
            .showFloatWindow(true)
            // 重启后清除本地所有文件(目前不支持展示历史数据,所以默认清除本地所有)
            .clearAllFileWhenRestartApp(true)
            // 运行时超出阈值就清理
            .clearFileWhenOutOfThreshold(false)
            // 本地图片缓存写入上限,单位为 byte,默认大小为 512MB,超出后会立刻删除
            .diskCacheLimitBytes(100 * 1024 * 1024L)
            .isDebug(true)
            .context(ctx)
            .build()
        BitmapMonitor.init(config)
java.lang.NullPointerException
	at java.io.File.<init>(File.java:283)
	at top.shixinzhang.bitmapmonitor.internal.BitmapFileWatcher.loadAllFileToMemory(BitmapFileWatcher.java:103)
	at top.shixinzhang.bitmapmonitor.internal.BitmapFileWatcher.$r8$lambda$hPaKz5jeLLZ9ow_IMx3UtPDtUb8(Unknown Source:0)
	at top.shixinzhang.bitmapmonitor.internal.BitmapFileWatcher$$ExternalSyntheticLambda0.run(Unknown Source:0)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
	at java.lang.Thread.run(Thread.java:923)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.