Bitmap OOM分析

论坛 期权论坛 脚本     
匿名网站用户   2020-12-21 07:24   118   0

遇到一个Bitmap OOM,但先入为主的认为是内存泄露问题。重点在一步步的分析中,根据数据得出崩溃原因。


Crash Log

    java.lang.OutOfMemoryError: Failed to allocate a 48771084 byte allocation with 16771032 free bytes and 29MB until OOM
        at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
        at android.graphics.Bitmap.nativeCopy(Native Method)
        at android.graphics.Bitmap.copy(Bitmap.java:592)

48771084 byte / 1024 / 1024 ~~ 约46.51M
16771032 byte ~~ 约 15.9941M


分析

使用Android Studio自带的Android Profiler

奔溃前的最大dump heap后最大的Bitmap

Bitmap参数
density:280
width:1920
height:1080
mBuffer[]: 8294400 
Size

~~~~
Crash 图片文件大小: 约76.3K 准确76251

1080P图片大小,RGBA 8888格式
每个通道占8bite = 1byte, 4通道图像的1个像素=4byte
1920*1080*4= 8294400B 8294400/1024/1024 = 7.9101MB
所以,1080P的图片在内存中占用不到8M.
~~~~

注意 发生OOM之前Heap dump出最大的Bitmap 不是崩溃时的,是之后的Bitmap

起初以为是内存泄露,但通过heap dump 出的信息,分析图片大小也就约8M,不可能崩溃让heap累计分配46M。后来通过log发现,是之后的图片导致的OOM,那个图文件是485.9kb

最后通过采样就ok了

采样代码



//        调用代码
//        Bitmap bitmap = BitmapUtils.getScaledBitmapFromFile(graphicFile.getAbsolutePath(),
//                1920, 1080);

    public static Bitmap getScaledBitmapFromFile(String filePath, int requiredWidth, int requiredHeight) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);
        options.inSampleSize = calculateInSampleSize(options, requiredWidth, requiredHeight);
        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //don't use same inputstream object as in decodestream above. It will not work because
        //decode stream edit input stream. So if you create
        //InputStream is =url.openConnection().getInputStream(); and you use this in  decodeStream
        //above and bellow it will not work!
        Bitmap bm = BitmapFactory.decodeFile(filePath, options);
        return bm;
    }


    /** 该方法即是计算图片缩放比例
     * options 原图的参数
     */
    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight
                    && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP