您的位置:首页 > 移动开发 > Android开发

Android Bitmap处理和内存管理与垃圾回收

2012-11-24 11:13 211 查看
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

具体手机可以通过ActivityManager.getMemoryClass()来获取Heap大小。Heap大小是动态分配的,有一个最小的初始值,然后会随内存分配动态增长,这是和标准jvm一样的。

这个值也可以通过更改/system/build.prop文件中的dalvik.vm.heapsize来改变。

对于GC的方式也是有区别的:

• Pre-Gingerbread GC:

– Stop-the-world

– Full heap collection

– Pause times often > 100ms

• Gingerbread and beyond:

– Concurrent (mostly)

– Partial collections

– Pause times usually < 5ms

最后,分析内存情况的话可以使用DDMS,dump出内存使用的情况,然后使用Eclipse Memory Analyzer (MAT)来分析内存使用情况。

Google IO 11有个Session是“memory_management_for_android_apps”部分参考了这个Session的内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: