Android Bitmap 内存以及OOM问题讨论
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Bitmap 内存以及OOM问题讨论相关的知识,希望对你有一定的参考价值。
参考技术A 都知道在android中, 每个应用所使用的内存是有限的,现在的手机通常最大的内存使用为256M, 目前还没发现Android中一个应用的最大内存分配超过256M的(经测试华为手机的最大内存是385M)相关API:
ActivityManager.getMemoryClass(),首先获取系统服务中的ActivityManager
如下:
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
可以获取到相关信息
最近一直被项目的OOM问题困扰, 在网上查阅相关资料,前前后后读了不下于30篇,这些篇幅讲解的东西都是千篇一律,并没有解决到实际问题
也在慕课网学习了内存优化章节
这是慕课网讲师的PPT,我截屏的
这里来仔细分析一下:
第一个, 注意临时Bitmap对象的及时回收, 来看下相关API
直接上图
经过我无数次的使用Android studio工具自带的MAT分析工具后, 得出一个很严谨的结论, 此方法并不奏效...
Android中Bitmap的内存存放在堆区, Google 的Bitmap的recycle方法注释也可以了解到
Android历史版本不是很清楚, 据说Android3.0之前Bitmap是存放在native区域,可以进行手动释放,然而3.0之后Bitmap是存放在Java层的堆区,没错是heap, 内存管理直接交由系统GC管理,你还这样释放资源有意义?无非是给自己的一点心理安慰罢了, 告诉你没卵用
又有人在说要释放内存使用System.gc() ??? 对就是主动触发垃圾回收,这个API是开发者自行调用的吗?那么系统管理内存还有什么意义?这不是误人子弟吗,这个API不能调用的, 因为没卵用的, 具体自己参照MAT工具自行分析.即便垃圾回收真的被触发了, 所有线程停滞由系统来清理垃圾, 造成的后果是严重卡顿!!!
再看一个API:
我在网上苦苦追寻内存过高的问题后,发现了这个API,经过无数次实践后我得出一个结论,没卵用...开发者可以抛弃它
综上所诉, 第一点讲解的内存优化问题可以直接PASS掉, 无非给自己一点心理安慰: 我已经处理好了内存问题, 程序不会OOM?
第二点. 避免Bitmap的浪费
直接说结论, 这个是非常行之有效的,并且是一定能解决问题的
具体怎么操作呢? 自己实现LruCache这个类, 就是这么弄, 原理就是解码复用, 在内存中已经解码好的Bitmap直接拿出来使用, 没有的在加载到内存进行解析, 这个非常有效,但是并不能让你避免OOM
第三点, try-catch某些大内存分配的操作
这点上,我又要开始疑问了, 我Java功底不是很好
Java中发生内存溢出时,抛出的是OutOfMemoryError, 它的父类是VirtualMachineError
这玩意能catch住? 它属于Error范畴, 你能捕获?请Java大神出来说一下,我解释不清楚
第四点, 加载Bitmap 缩放比例, 解码格式, 局部加载
先来分析一下缩放比例:
按照市面上主流的手机分辨率来分析现在Android主流的分辨率是1920X1080, 如果一个ImageView控件刚好就是屏幕全屏,怎么说?直接占用掉8M内存, 想想一个实际的需求情况
一个查看大图的页面, 不断的关闭,打开查看新的大图,问题就来了,内存一直在暴增,迟早会突破界限OOM掉
分辨率是2K屏呢? 更恐怖了, 随着手机设备的屏幕分辨率提升, 加载图像需要的内存也是倍增的, 因为应用的最大内存并没有增加
结论: 缩放比例可以有效的降低内存占用问题, 但不是绝对的救命稻草, 该缩放的还是要缩放,而且必须缩放,就是采样 现在通常都是图片加载框架来完成,类似Glide.Picasso,Fresco等,他们可以帮助你减少工作量, 内存问题还是存在
再来分析一下解码格式:
这个跟缩放比例效果差不多, 只是同样的分辨率的图片加载到内存中时占用内存减少了
比如ARGB_8888 共32位
RGB_565 共16位
ARGB_4444 共16位
很明显这样格式图片加载的内存情况是ARGB_8888是其他格式的两倍内存
另外的问题是ARGB_8888看起来很清晰的, 其它的看起来图片有种糊了的感觉,自己选择吧
结论, 降低内存占用非常有效
最后一个是局部加载, 并没有怎么使用到,也不清楚就不说了
最后还有一个方法避免OOM, 开启largeHeap属性, 但是但是, 以前我们开启这个属性后被Oppo应用市场认定为占用内存过高, 不建议用户安装......所以我们又取消了!
总的来说, Bitmap在内存是变现的是不可控, 我项目OOM问题一直没有得到有效解决,因为图片编辑视频编辑之类的功能占用内存过高,继续使用OOM是必然的, 跟ios的同学交流了一番,他们说IOS的应用内存可以占用到1个G以上, 轻松跑到500M是没问题的, IOS的内存机制可以持续给内存使用, 具体我也不清楚,并且他们可以手动释放内存?malloc, free这样子?
如果大家有比较好的方案,还望留言交流互相帮助 [笑脸.gif]
补充: Android8.0开始Bitmap数据内存存在native层, 单个应用可用的内存显著增长, 极大的降低了OOM的概率(2018年3月22日)
bitmap 内存溢出OOM的解决办法分享
昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bitmap报的错。第一次调用都没问题,第二次再次调用就会报上面那个内存溢出的问题。而且有的手机报有的手机不报。研究了半天终于解决。首先分析了下原因,应该是图片占用的内存超过了系统虚拟机可分配的最大限制。不同手机可能分配的最大值不一样。后来找到解决办法主要是设置BitmapFactory.Options。
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); bitmapOptions.inSampleSize = 4; bitmap = BitmapFactory.decodeStream(this.getContentResolver()..openInputStream(uri), null , bitmapOptions);
有的说要加上bitmapOptions.inJustDecodeBounds = true;但是我加上后得到的bitmap就为null。去掉之后就可以。按照上面的方法就解决问题了。最好把bitmap在不用的时候回收一下:
if (bitmap != null && !bitmap.isRecycled()) bitmap.recycle();
某位大神的图片占用内存的算法:
介绍一下图片占用进程的内存算法吧。
android中处理图片的基础类是Bitmap,顾名思义,就是位图。占用内存的算法如下:
图片的width*height*Config。
如果Config设置为ARGB_8888,那么上面的Config就是4。一张480*320的图片占用的内存就是480*320*4 byte。
前面有人说了一下8M的概念,其实是在默认情况下android进程的内存占用量为16M,因为Bitmap他除了java中持有数据外,底层C++的skia图形库还会持有一个SKBitmap对象,因此一般图片占用内存推荐大小应该不超过8M。这个可以调整,编译源代码时可以设置参数。
// Eliminate extra GCs during startup by setting the initial heap size to 4MB. // TODO: We should restore the old heap size once the activity reaches the idle state VMRuntime.getRuntime().setMinimumHeapSize(INITIAL_HEAP_SIZE);
以上是关于Android Bitmap 内存以及OOM问题讨论的主要内容,如果未能解决你的问题,请参考以下文章