android 内存

http://phenom.iteye.com/blog/1679198

这篇是翻译的, 
此次是实践,是关于Android系统的图片解码的实例 

Java代码     收藏代码
  1. 文中说到:  
  2. 摄像头在GalaxyNexus拍一张照片有2592*1936像素,如果bitmap使用ARGB_8888配置(2.3默认的),加载这张照片到内存需要消耗约19mb内存,(2592*1936*4bytes)  
  3. 19m的内存对模拟器的16m来说,显然太大了,但对于真实的机器 ,还是可以的  
  4.   
  5. 至于说Android的图片内存8m,这个不知道是听谁说的,总之我也没有找到标准的答案,有可能是在Android刚出来的时候定义的一个堆大小,我觉得最有可能的是这个值作为图片解码的内存大小,却不是对图片的大小限制的.所以上面的图片是可以解码显示出来的.  
  6.   
  7. 先说下情况:  
  8. 一张440*17514大小的图片,直接在galaxy上解析,然后得到Bitmap,再放到ImageView中显示,一切正常的.说下galaxy的情况:  
  9. /system/build.prop中的heapsize=64m  
  10. 两种方法,一种是argb_8888配置,一种 是rgb_565  
  11.   
  12. 实践也表明了,两种图片解码后的效果差不多的,如果不是图像处理,完全可以用rgb_565来处理图片的显示,  
  13.   
  14. 显然这张图片解析需要29m左右的内存,<64m.所以我觉得Android的内存限制不是只是图片上,而是整个进程的,当进程占用的内存没有超过这个值,就是正常的,而,解析图片通常是最耗内存的操作.  
  15.   
  16. 在ImageView中显示一张,argb_8888,然后再解码一次,29*2+其它的操作,对象内存,勉强>64m了,只能解码一次.  
  17. 使用rgb_565解码一次15m左右,可以有四次的机会,为什么不是三次呢,29*2<64,但一次解析大图,消耗的其它对象内存也大了.  
  18.   
  19. 于是修改了/system/build.prop中的heapsize=48m,重启了,  
  20. 再运行,argb_8888一次解码正常的.二次崩溃.  
  21. 使用rgb_565解码,可以两次,三次崩溃.  
  22.   
  23. 于是修改了/system/build.prop中的heapsize=24m,重启了,  
  24. 再运行,argb_8888一次崩溃.  
  25. 使用rgb_565解码,可以一次,第二次崩溃.  
  26.   
  27. ,由此可见,不是一张大的图不可以显示出来,通常一张拍摄的照片像2592*1936这样的,有这样的分辨率,就有相应的机器对应,所以内存也就大了,不是所谓的8m.  
  28.   
  29. 由于只分析了一些实践结果,对系统的代码没有研究,有可能这是不对的,或许  
  30. c对解码图片作了一些内存上的限制.  
  31.   
  32. 但是可以知道,8m的内存是不对的,即使现在新机器中最烂的也不小于512m的内存,heapsize也>24m,所以对于上面这种大的图片,使用rgb_565解码,是没有问题的.  
  33.   
  34. final int memClass = ((ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();  
  35.         System.out.println("memClass:"+memClass);  
  36.   
  37. 可以得到这个值的大小.  
  38.   
  39. 最近做的微博程序中大图浏览直接崩溃,内存不足,64m的内存,缓存各种图片64张,图片大小大约是在400*1600,几十张图片加载后就崩溃了.  
  40.   
  41. 当然如果没有必要,还是缩放一下较好:  
  42. BitmapFactory.Options options = new BitmapFactory.Options();  
  43. 使用缩放的效果明显要比使用rgb_565解码糟糕的多了. 

 

 http://www.linuxidc.com/Linux/2013-04/82441p3.htm

明明还有很多内存,但是发生OOM了。

这种情况经常出现在生成Bitmap的时候。有兴趣的可以试一下,在一个函数里生成一个13m 的int数组。

再该函数结束后,按理说这个int数组应该已经被释放了,或者说可以释放,这个13M的空间应该可以空出来,

这个时候如果你继续生成一个10M的int数组是没有问题的,反而生成一个4M的Bitmap就会跳出OOM。这个就奇怪了,为什么10M的int够空间,反而4M的Bitmap不够呢?

这个问题困扰很久,在网上,国外各大论坛搜索了很久,一般关于OOM的解释和解决方法都是,如何让GC尽快回收的代码风格之类,并没有实际的支出上述情况的根源。

直到昨天在一个老外的blog上终于看到了这方面的解释,我理解后归纳如下:

Android中:

1)、一个进程的内存可以由2个部分组成:java 使用内存 ,C 使用内存 ,这两个内存的和必须小于16M,不然就会出现大家熟悉的OOM,这个就是第一种OOM的情况。

2)、更加奇怪的是这个:一旦内存分配给Java后,以后这块内存即使释放后,也只能给Java的使用,这个估计跟java虚拟机里把内存分成好几块进行缓存的原因有关,反正C就别想用到这块的内存了,所以如果Java突然占用了一个大块内存,即使很快释放了:

C能使用的内存 = 16M - Java某一瞬间占用的最大内存。

而Bitmap的生成是通过malloc进行内存分配的,占用的是C的内存,这个也就说明了,上述的4MBitmap无法生成的原因,因为在13M被Java用过后,剩下C能用的只有3M了。

5、在Android平台下实现OpenGL ES程序的贴图加载操作一般是通过BitmapFactory.decodeResource这个api,然后用系统封装好的 GLUtils.texImage2D函数直接转换为gl贴图即可,方便快捷。但在较新版的Android系统中res中的图片文件夹根据dpi设备分辨率的不同,细分了很多文件夹处理以支持不同设备的分辨率加载对应的图片,如drawable-hdpi,drawable-ldpi,drawable- mdpi等,如果没有注意这个问题而将贴图图片随意安置的话,在decode的时候系统会默认根据设备dpi的不同对目标图片格式解码的同时进行大小调整,也就是说有可能破坏原本已经是2^n大小的贴图图片,导致原本在模拟器上正确的绘图在真机上变成大白板!解决这个问题的方法可以将图片放到不受dpi影响的drawable-nodpi中,或者设置BitmapFactory的选项,不处理dpi相关问题。

6、查询内存限制大小:

ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
activityManager.getMemoryClass();

以上方法会返回以 M 为单位的数字,可能在不同的平台或者设备上值都不太一样,比如:HTC G7 默认 24M,Galaxy 36M,emulator-2.3 24M,等等。

你可能感兴趣的:(android)