Android 开发绕不过的坑 你的 Bitmap 究竟占多大内存

               
 

未标题-2.jpg (60.35 KB, 下载次数: 9)

下载附件

2016-1-14 17:36 上传


Bugly 技术干货系列内容主要涉及移动开发方向,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,转载请标明出处。

0、写在前面
本文涉及到屏幕密度的讨论,这里先要搞清楚 DisplayMetrics 的两个变量,摘录官方文档的解释:


  • density:The logical density of the display. This is a scaling factor for the Density Independent Pixel unit, where one DIP is one pixel on an approximately 160 dpi screen (for example a 240x320, 1.5”x2” screen), providing the baseline of the system’s display. Thus on a 160dpi screen this density value will be 1; on a 120 dpi screen it would be .75; etc.
    This value does not exactly follow the real screen size (as given by xdpi and ydpi, but rather is used to scale the size of the overall UI in steps based on gross changes in the display dpi. For example, a 240x320 screen will have a density of 1 even if its width is 1.8”, 1.3”, etc. However, if the screen resolution is increased to 320x480 but the screen size remained 1.5”x2” then the density would be increased (probably to 1.5).
  • densityDpi:The screen density expressed as dots-per-inch.

简单来说,可以理解为 density 的数值是 1dp=density px;densityDpi 是屏幕每英寸对应多少个点(不是像素点),在 DisplayMetrics 当中,这两个的关系是线性的:
density 1 1.5 2 3 3.5 4
densityDpi 160 240 320 480 560 640
为了不引起混淆,本文所有提到的密度除非特别说明,都指的是 densityDpi,当然如果你愿意,也可以用 density 来说明问题。
另外,本文的依据主要来自 android 5.0 的源码,其他版本可能略有出入。文章难免疏漏,欢迎指正~

1、占了多大内存?

做移动客户端开发的朋友们肯定都因为图头疼过,说起来曾经还有过 leader 因为组里面一哥们在工程里面加了一张 jpg 的图发脾气的事儿,哈哈。
为什么头疼呢?吃内存呗,时不时还给你来个 OOM 冲冲喜,让你的每一天过得有滋有味(真是没救了)。那每次工程里面增加一张图片的时候,我们都需要关心这货究竟要占多大的坑,占多大呢?Android API 有个方便的方法,
[Java]  纯文本查看  复制代码
?
1
2
3
4
public final int getByteCount() {
     // int result permits bitmaps up to 46,340 x 46,340
     return getRowBytes() * getHeight();
}

通过这个方法,我们就可以获取到一张 Bitmap 在运行时到底占用多大内存了。


举个例子
一张  522x686 的  PNG 图片,我把它放到  drawable-xxhdpi 目录下,在 三星s6上加载,占用内存2547360B,就可以用这个方法获取到。



2、给我一张图我告诉你占多大内存
每次都问 Bitmap 你到底多大啦。。感觉怪怪的,毕竟我们不能总是去问,而不去搞清楚它为嘛介么大吧。能不能给它算个命,算算它究竟多大呢?当然是可以的,很简单嘛,我们直接顺藤摸瓜,找出真凶,哦不,找出答案。

2.1 getByteCount
getByteCount 的源码我们刚刚已经认识了,当我们问 Bitmap 大小的时候,这孩子也是先拿到出生年月日,然后算出来的,那么问题来了,getHeight 就是图片的高度(单位:px),getRowBytes 是什么?
[Java]  纯文本查看  复制代码
?
1
2
3
4
5
6
public final int getrowBytes() {
    if (mRecycled) {
           Log.w(TAG, "Called getRowBytes() on a recycle()'d bitmap! This is undefined behavior!" );
    }
    return nativeRowBytes(mFinalizer.mNativeBitmap);
}

额,感觉太对了啊,要 JNI 了。由于在下 C++ 实在用得少,每次想起 JNI 都请想象脑门磕墙的场景,不过呢,毛爷爷说过,一切反动派都是纸老虎~与

nativeRowBytes 对应的函数如下:
Bitmap.cpp
[Java]  纯文本查看  复制代码
?
1
2
3
4
static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) {
      SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle)
      return static_cast<jint>(bitmap->rowBytes());
}

等等,我们好像发现了什么,原来 Bitmap 本质上就是一个 SkBitmap。。而这个 SkBitmap 也是大有来头,不信你瞧: Skia。啥也别说了,赶紧瞅瞅 SkBitmap。
SkBitmap.h
[Java]  纯文本查看  复制代码
?
1
2
/** Return the number of bytes between subsequent rows of the bitmap. */
size_t rowBytes() const { return fRowBytes; }

SkBitmap.cpp
[Java]  纯文本查看  复制代码
?
01
02
03

猜你喜欢

转载自blog.csdn.net/qq_43667155/article/details/86676349