Android Bitmap处理和内存管理与垃圾回收
2012-11-24 11:13 onm 阅读(774) 评论(0) 编辑 收藏 举报
Android3.0之前的手机,通过DDMS观看Heap信息的时候不显示native部分分配的内存大小,如图所示,加载了一张7M多的图片,但是显示分配Allocated才2M多。但是native分配的内存大小是算在heap上的,所以当heap大小显示的不是HeapMaxSize的时候,也有可能oom。
下图是Android3.0之前Bitmap的内存管理方式。
3.0以后情况。
3.0以后Bitmap内存管理方式。
3.0以后Bitmap分配的内存是受GC管理的内存,分配站Heap上,可以通过GC回收。3.0之前是freed via recycle() or finalizer。
3.0以前LogCat会出现类似external_alloc相关字样,应该就是上图中Native中分配的内存。
还有GC_EXTERNAL_ALLOC,表示GC to try to reduce heap footprint to allow more non-GC'ed memory.
可以通过GC_EXPLICIT freed <1K, 50% free 2718K/5379K, external 19447K/21495K, paused 54ms,观察到external的内存占用,使用了19447K,总共21495K。free后面显示的是分配在Heap上的内存。
网上有这么说的“external是指VM中通过JNI中Native的类中的malloc分配出的内存,例如Bitmap和一些Cursor都是这么分配的”。
而且发现,通过BitmapFactory decode的时候,Android4.0和Android2.3分配的内存空间是不一样的,Android4.0分配的空间是Android2.3的2倍。(没有具体考察具体的分界线是哪个版本)
这个可以在decode的时候通过设置Options来更改,inPreferredConfig属性决定了,Bitmap.Config类型,Config有常用的有RGB_565,ARGB_8888两种,正好对应了刚才说的情况。RGB_565是每个像素用2个字节存储,只存储R、G、B信息,分别占用5、6、6个bit,没有alpha信息。而RGB_8888是每个像素用4个字节存储,A、R、G、B分别用8bit存储。当然这种图片的质量更高。
还有一个疑问是我的图片是7.8M的一张图片,但是加在到内存占用了17M多的内存,这个正是刚才说的,比如这个图的尺寸是3488 × 2616,所以就有3488 × 2616个像素点,使用RGB_565的时候,每个像素点用2个字节存储。3488 × 2616 x 2正好就是17M多。
加载大图片的通常做法是,先通过设置Options.inJustDecodeBounds属性为true,这样decode的时候只会decode图片尺寸信息,通过Options.outHeight和outWidth取得。然后和希望的最大宽高值计算出inSampleSize。
The sample size is the number of pixels in either dimension that correspond to a single pixel in the decoded bitmap. For example, inSampleSize == 4 returns an image that is 1/4 the width/height of the original, and 1/16 the number of pixels.
也就是说横向和纵向用sample size个点表示一个点。例如,inSampleSize == 4,返回一个原来宽高的1/4的图片,有原来像素数的1/16。
另外,不同机型的Heap最大大小是不一样的,一些机型
Heap size limits
- – G1: 16MB
- – Droid: 24MB
- – Nexus One: 32MB
- – Xoom: 48MB
- – Stop-the-world
- – Full heap collection
- – Pause times often > 100ms
- – Concurrent (mostly)
- – Partial collections
- – Pause times usually < 5ms