bingoogolapple.github.io
bingoogolapple.github.io copied to clipboard
Android Bitmap 知识点整理
Android中图片占用内存的计算
Android中一张图片(Bitmap)占用的内存=图片长度 x 图片宽度 x 单位像素占用的字节数 注:图片长度和图片宽度的单位是像素。
创建一个Bitmap时,其单位像素占用的字节数由其参数BitmapFactory.Options的inPreferredConfig变量决定。inPreferredConfig为Bitmap.Config类型,它可以为以下值
图片格式(Bitmap.Config) | 占用内存的计算方式 | 一张100*100的图片占用内存的大小 |
---|---|---|
ALPHA_8代表8位Alpha位图 | 图片长度*图片宽度 | 100 * 100=10000字节 |
ARGB_4444代表16位ARGB位图 | 图片长度*图片宽度 * 2 | 100 * 100 * 2=20000字节 |
ARGB_8888代表32位ARGB位图 | 图片长度*图片宽度 * 4 | 100 * 100 * 4=40000字节 |
RGB_565代表8位RGB位图 | 图片长度*图片宽度 * 2 | 100 * 100 * 2=20000字节 |
另外,需要注意这里的图片占用内存是指在Navtive中占用的内存,当然Bitmap使用的绝大多数内存就是该内存。 因为我们可以简单的认为它就是Bitmap所占用的内存。 Bitmap对象在不使用时,我们应该先调用recycle(),然后才它设置为null。 虽然Bitmap在被回收时可以通过BitmapFinalizer来回收内存。但是调用recycle()是一个良好的习惯。 Android 2.3 之前 Bitmap 的引用是放在堆中的,而 Bitmap 的数据部分是放在栈中的,需要用户调用recycle 方法手动进行内存回收,而在 Android 2.3 之后,整个 Bitmap 包括数据和引用都放在了堆中
- 无论图片质量好坏,加载到内存中占用内存的大小只与图片大小、Config图片质量参数配置有关,压缩图片只是让打包的apk减小,而运行时的内存大小是无关的。
- 调用recycle之后,虽然不立即释放,但当内存不足时还是会去释放的,并分配给新对象
- 图片显示到imageView 和 解码到bitmap,占用内存一样多; activity finish后,可能不会立即释放内存,但内存不足时应该是会释放掉的,只要这个activity里的对象没被其他类引用;所以android里不用过于关注activity里各种内存占用、释放,只要引用不被其他类引用
- xml里设置ImageView的src 和 代码中设置imageResource占用的内存一样多。那么如果imageView的width 不是wrap_content呢?比如 width=100,height=150,经测试,占用的内存情况与上述wrap_content完全相同; 看来android底层加载图片时,也没有进行内存优化,未根据imageView控件大小对图片做缩放后再加载进来;或者什么原因不优化
- 根据图片控件的宽高来计算BitmapFactory.Options的inSampleSize属性的值来优化Bitmap加载内存
- 创建一个空的bitmap 480 * 800, 占用的内存大小是不是与 加载一张480 * 800的图片大小一样。bitmap占用内存大小 与三个因素有关: width 、height、config质量参数
- android bitmap占用的内存代码直接计算bitmap.getRowBytes() * bitmap.getHeight()
- PC上看 480 * 800的图片,读入内存bitmap后大小 getWidth getHeight值变了,getWidth: 640, getHeight: 1067。drawable存放目录导致,我放在drawable-hdpi目录下,机型是 720 * 1080分辨率的(320密度),改放在 drawable-xhdpi目录下,bitmap.getWidth() 值就与预期一致了为480
- drawable目录,android图片处理有自动缩放功能,如果xhdpi的机型,读取hdpi目录,则会认为图适配的机型是hdpi,用在 xhdpi的机型需要等比例放大
打印当前程序占用的内存
public static void printMem(String when) {
//程序可用的最大内存
float maxMem = Runtime.getRuntime().maxMemory() / 1024 / 1024;
//程序当前占用的内存
float totalMem = Runtime.getRuntime().totalMemory() / 1024 / 1024;
//freeMem != maxMem - totalMem
//我理解 freeMem应该是 当前分配给该程序的内存 - totalMem, 当前分配给程序的内存时动态的(在小于maxMem范围内)
//同virtualbox安装的ubuntu虚拟机占用内存类似,设置个最大内存,但实际占用内存时动态分配的
float freeMem = Runtime.getRuntime().freeMemory() / 1024 / 1024;
bm(when + ": maxMem | totalMem | freeMem : " + maxMem + "M|" + totalMem + "M|" + freeMem + "M");
}