`

Android技术积累:图片缓存管理

阅读更多

缓存:   本文链接地址:http://keegan-lee.diandian.com/post/2012-12-06/40047548955

 

 

 

android 由解析bitmap引起的内存溢出问题

最近在做一款塔防游戏,用的事surfaceview框架,由于图片过多,而且游戏过程中都需要这些图片,所以加载成bitmap后造成OOM(out of memory)异常。下面是我一步一步找解决此问题的纪录,再此分享,希望对以后出现此问题的开发者有所帮助。

第一:出现问题,我的测试手机是2。2android操作系统,不会出现oom问题,但是在老板的android4.2上却出现了问题,因为是 oom,所以我首先想到的是手动改变手机的内存大小限制。网上有些帖子说可以通过函数设置应用的HEAP SIZE来解决这个问题,其实是不对的。 VMRuntime.getRuntime().setMinimumHeapSize(NewSize); 堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M 大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候, 缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。Max Heap Size,是堆内存的上限值,Android的缺省值是16M(某些机型是24M),对于普通应用这是不能改的。函数 setMinimumHeapSize其实只是改变了堆的下限值,它可以防止过于频繁的堆内存分配,当设置最小堆内存大小超过上限值时仍然采用堆的上限 值,对于内存不足没什么作用。 setTargetHeapUtilization(float newTarget) 可以设定内存利用率的百分比,当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。在手机上进行了多 次测试,确实不好使,在此,我断了改变内存限制的方法。

第二:查找出现问题的原因。1,在网上搜索bitmap内存溢出,找到很多说是因为图片大小引起的此问题。观察我的资源文件,没有太大的图片,只是图片数量过多,有将近900张,分别找出一张最大的图片和几张比较大的图片,单独测试,没有发现问题。方法1排除。

2,既然图片数量过多,突破点可能就是图片数量问题。于是分别找了200,400,600图片进行测试,在500左右的时候遇到错误,通过宝哥知道 了将小图片整合存放到一张大图的方法,以此来减少图片的数量,但是仔细想想,加载成bitmap的时候还是要切割成小图生成bitmap,所以对此方法表 示怀疑。由于以前没用过此方法,试试也无妨。所用到的工具是gdx—texturepackger,它只是一个工具,这里就不多说了。测试的最终结果是还 是oom。方法2排除。

3,现在看来,既然不是图片数量的问题,而且会在500张左右的时候报错,那就可能是占用内存大小的问题了,Android手机有内存限制,但是我 的图片大小又大于这个限制,这让我头疼了很长时间,研究国外的一些文章,从中发现了一些有用的信息,这些信息能够加深你对Android的解析 bitmap机制的理解,在此分享:

As of Honeycomb Bitmap data is allocated in the VM heap.

作为蜂窝位图数据是在VM分配堆。)

There is a reference to it in the VM heap (which is small), but the actual data is allocated in the Native heap by the underlying Skia graphics library. 有一个引用在VM堆(小),但实际的数据是在本机堆分配由底层Skia图形库。
Unfortunately, while the definition of BitmapFactory.decode…() says that it returns null if the image data could not be decoded, the Skia implementation (or rather the JNI glue between the Java code and Skia) logs the message you’re seeing (“VM won’t let us allocate xxxx bytes”) and then throws an OutOfMemory exception with the misleading message “bitmap size exceeds VM budget”. 不幸的是,虽然BitmapFactory.decode的定义…()表示,它返回null如果图像数据不能解码,Skia实现(或者说JNI胶之间的 Java代码和Skia)日志消息你看到(“VM不会让我们分配xxxx字节”),然后抛出一个OutOfMemory异常与误导信息”位图的大小超过 VM预算”。
The issue is not in the VM heap but is rather in the Native heap. 这个问题不是在VM堆而是在本机堆。
The Natïve heap is shared between running applications, so the amount of free space depends on what other applications are running and their bitmap usage. 本机堆是正在运行的应用程序之间共享,因此空闲空间的大小取决于其他运行程序,他们使用的位图。

However, I have found that getNativeHeapFreeSize() and getNativeHeapSize() are not reliable. 然而,我发现getNativeHeapFreeSize()和getNativeHeapSize()是不可靠的。

The Native heap size varies by platform. 本机堆大小不同的平台。
So at startup, we check the maximum allowed VM heap size to determine the maximum allowed Native heap size. 所以在启动时,我们检查最大允许VM堆大小来确定最大允许本机堆大小。

“Bitmap data is not allocated in the VM heap” — it is allocated on the VM heap as of Honeycomb “位图数据不是在VM分配堆”——这是VM分配的堆在蜂窝Yes. 是的。 As of Honeycomb (v3.0), bitmap data is allocated on the VM heap. 作为蜂窝(v3.0),位图数据堆上分配VM。 So all of the above only applies to Gingerbread (v2.3.x) and before 所以所有上述只适用于姜饼(v2 3 x)和之前

这些信息零零散散,但是不难发现,问题的原因就在于根据Android版本的不同,bitmap data存放的位置是不同的,3.0以前是分配在native heap上,3.0以后是分配在VM heap上。

为了验证这个问题,我们需要抓去heap快照,众所周知,eclipse中的ddms可以查看heap信息,但是不够全面,这里我用到了adb shell dumpsys meminfo+包名 这条命令来查看heap信息,对比两个机子的不同如下:

2.2的

4.0

从中不难发现,bitmap的存放位置根据Android版本的不同真的有所不同。 好了,下面就是找出怎么把图片存放到native heap里就行了,BitmapFactory里就那么几个decode方法,很容易找到BitmapFactory .decodeStream就可以解决。下面贴一下代码:

BitmapFactory.Options options = new BitmapFactory.Options();

options.inPreferredConfig = Config.ARGB_8888;

options.inPurgeable = true;// 允许可清除

options.inInputShareable = true;// 以上options的两个属性必须联合使用才会有效果

String sname = String.format( “xxx.png”, sTowerStyle, j, sDirction, i);

InputStream is = am.open(sname);

arrBmp[ iBmpIndex] = BitmapFactory .decodeStream(is, null, options);

ok搞定收工。

小问题大发现:1.遇到问题,不要急躁。最初遇到这个问题的时候以为很好解决,试了几种方法后还是解决不了,内心难免会有挫败感,这个时候,最需要的是耐心。

2.网上有很多资源,但是能不能查得到就是自己的问题了,我发现那些编程老手们查找问题总是能够准确定位,快速的找到解决方法。以后要加强这方面的锻炼。

3.国内的资源大多偏向解决问题,国外的资源大多偏向分析问题,所以有的时候还是需要多看看外文的一些资料。当然这需要不错的英文功底。当初看外文的资料,头都大了。这是需要加强的一个方面。

Dance In Wind     28/10/12

 

 

 

 

 

Bitmap.Config下面有4个参数:

 

Java代码 
Bitmap.Config  ALPHA_8     
Bitmap.Config  ARGB_4444     
Bitmap.Config  ARGB_8888     
Bitmap.Config  RGB_565  

 


首先
Java代码 
A:Alpha透明度 
R:Red红色 
G:Green绿色 
B:Blue蓝色 

 


然后

 

Java代码 
Bitmap.Config  ALPHA_8    图形参数应该由一个字节来表示,应该是一种8位的位图 
Bitmap.Config  ARGB_4444  图形的参数应该由两个字节来表示 分别用4个bit来记录每个像素的A、R、G、B数据,16色位图 
Bitmap.Config  ARGB_8888  图形的参数应该由四个字节来表示 分别用8个bit来记录每个像素的A、R、G、B数据,就是常说的32bit位图、256色位图(这个也可能是RGB888这种24bit位图)   
Bitmap.Config  RGB_565 图形的参数应该由两个字节来表示 分别用5个、6个和5个bit记录像素的R、G、B数据,其中G的6个bit中一个是无效保留的,32色位图 

 


一般情况下我们都是用ARGB_8888    但是它也相对的很占内存
因为一个像素8+8+8+8=32位  8位一个字节  也就是一个像素4个字节 如果是800*480的图片的话 也就是 800*480*4/1024/124  估计也有1M多了 
所以作为手机应用开发人员你使用的内存是有限的

作者“TryLoveCatch”

分享到:
评论

相关推荐

    Android图片缓存管理

    Android技术积累 图片缓存管理 ,适用于android特性

    Android高薪之路:Android程序员面试宝典

    另外,掌握Android资源管理,包括布局XML、图片优化、主题和样式等,能够提升应用的用户体验。 再者,UI设计与性能优化是提升应用质量的关键。使用 ConstraintLayout、RecyclerView 和其他布局管理器构建响应式界面...

    android手把手开发一个图片浏览器

    - 实现图片缓存机制,避免频繁网络请求导致的延迟问题。 - 支持多种图片格式如JPEG、PNG等,并处理图片压缩以优化性能。 4. **手势操作**: - 添加触摸事件监听器来识别用户手势(如滑动、缩放)。 - 实现双击...

    新浪微博客户端Android源码

    《深入剖析:新浪微博客户端Android源码》 在移动开发领域,Android平台因其开源特性而备受开发者...虽然难度较大,但持之以恒的学习和研究,定能收获丰厚的技术积累。记住,每一个细节都可能是你技术成长的垫脚石。

    仿京东android客户端

    6. **图片加载**:应用可能涉及大量图片,因此需要合理处理图片缓存,比如使用Glide或Picasso库。 7. **列表滚动优化**:在商品列表页面,使用RecyclerView替代ListView,配合DiffUtil进行数据对比,提高滚动性能。...

    AndroidAndroid典型案例

    例如,使用MediaPlayer类处理音频,SurfaceView和TextureView处理视频,以及Bitmap和 Glide 库进行图片加载和缓存。 7. **碎片(Fragment)**:随着大屏幕设备的普及,Fragment成为了实现多屏适配的重要工具。理解...

    Android平板电脑开发实战详解和典型案例

    - **离线下载**:支持文章或图片的离线缓存功能。 - **个性化推荐**:根据用户的阅读习惯进行内容推荐。 #### 6. 游戏开发 - **图形渲染**:利用OpenGL ES等技术提高游戏画质。 - **动画效果**:添加动态效果提升...

    Android源码——小米文件管理器源码.zip

    通过深度剖析小米文件管理器的源码,开发者可以提升对Android系统、文件操作、UI设计、性能优化等多个方面的理解,为自己的项目开发积累宝贵经验。同时,这也是一个学习Android最佳实践、提升编程技巧的好机会。

    58同城Android客户端Walle框架演进与实践之路

    3. 动态化与插件化开发实践:包括缓存管理、动态部署、插件机制的运用,以及在实际操作中遇到的进程管理、代码共用等挑战。 4. 实践中的优化策略:为了应对如进程数膨胀、单例问题、插件交互复杂性增加等挑战,所...

    android代码库

    在Android开发中,图片加载是一个常见且重要的任务,涉及到网络图片的下载、缓存、内存管理等多个方面。通常,开发者会使用如Glide、Picasso、Universal Image Loader等开源库来处理这个问题。而`ImageLoader`可能...

    高清彩版 Android High Performance Programming (2018)

    **Diego Grancini**:虽然本书未详细介绍第二位作者的信息,但可以推测他也是一位资深的Android开发者,拥有丰富的实践经验和技术积累。 #### 三、核心知识点概览 ##### 1. 性能优化基础知识 - **理解性能瓶颈**...

    Android 源码实例项目 口袋微博

    通过研究口袋微博这个项目,开发者不仅能提升Android开发技术,还能了解社交应用的设计思路和实现方法,为今后的项目开发积累宝贵经验。同时,这样的开源项目也是学习新技术、解决实际问题的绝佳实践平台。

    Android程序员简历最新版

    7. **Android开发**:精通Android控件,尤其是四大组件的使用,熟悉ListView优化、图片缓存、XML和JSON解析、数据存储、Handler和AsyncTask,还了解消息推送机制和屏幕适配。 8. **网络通信**:理解Socket和HTTP协议...

    基于android的任务管理器的设计说明.doc

    清理缓存功能可以清除应用产生的临时数据,释放存储空间,防止设备因缓存积累而变得缓慢。同时,查看已安装软件列表可以帮助用户了解设备上所有应用的状态,便于管理和卸载不常用或冗余的应用,进一步优化性能。 在...

    深入Android开发全方位指南.docx

    ### 深入Android开发全方位指南 #### 一、Android 开发介绍与基础...综上所述,深入学习 Android 开发不仅需要掌握理论知识,更要在实践中不断积累经验。希望这份全方位指南能够帮助你在 Android 领域取得更好的成绩!

    Android 小项目 集合 使用工具 100多个

    6. **图片加载与处理**:如Glide、Picasso等库的使用,理解图片缓存策略。 7. **权限管理**:学习如何处理运行时权限,理解Android的权限模型。 8. **文件操作**:包括读写文件,理解文件路径和URI,以及文件选择...

    Android高仿拉手网项目实战视频教程下载

    - **Glide**:优秀的图片加载库,支持缓存管理。 - **Picasso**:另一个常用的图片加载库。 **5.2 内存管理** - 监控应用程序内存使用情况,避免内存泄漏。 - 合理利用缓存策略,减少重复加载。 **5.3 线程管理**...

    android手把手开发一个图片浏览器(pdf74).pdf

    接下来,我们将详细解析在开发Android图片浏览器过程中可能遇到的核心概念、技术细节以及最佳实践。 ### 核心概念 1. **Android SDK(Software Development Kit)**:这是进行Android应用开发的基础工具包,包含了...

    android仿微信界面demo

    8. **图片加载库**: 对于图片的加载和缓存,通常使用第三方库如Glide或Picasso,这些库可以优化内存管理和加载速度。 9. **通知与推送**: 微信实时推送新消息,这需要理解Android的Notification系统和后台服务。...

    android图片浏览器,没有内存溢出

    本项目“android图片浏览器,没有内存溢出”显然着重于解决这一问题,它采用了有效的内存管理策略和优化技术来避免内存溢出。 首先,让我们了解Android中处理大图和防止内存溢出的一些关键点: 1. **Bitmap对象的...

Global site tag (gtag.js) - Google Analytics