代码改变世界

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

2012-11-24 11:13 onm 阅读(...) 评论(...) 编辑 收藏
Android3.0之前的手机,通过DDMS观看Heap信息的时候不显示native部分分配的内存大小,如图所示,加载了一张7M多的图片,但是显示分配Allocated才2M多。但是native分配的内存大小是算在heap上的,所以当heap大小显示的不是HeapMaxSize的时候,也有可能oom。 ddms内存使用量截图 下图是Android3.0之前Bitmap的内存管理方式。 android3.0之前管理内存方式 3.0以后情况。 android3.0以后ddms内存使用截图 3.0以后Bitmap内存管理方式。 android3.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的内容。