首页编程java编程java bitmap是什么,Android Bitmap 内存以及OOM问题讨论

java bitmap是什么,Android Bitmap 内存以及OOM问题讨论

编程之家 2023-10-11 129次浏览

大家好,今天来为大家分享java bitmap是什么的一些知识点,和Android Bitmap 内存以及OOM问题讨论的问题解析,大家要是都明白,那么可以忽略,如果不太清楚的话可以看看本篇文章,相信很大概率可以解决您的问题,接下来我们就一起来看看吧!

java bitmap是什么,Android Bitmap 内存以及OOM问题讨论

Android Bitmap 内存以及OOM问题讨论

都知道在Android中,每个应用所使用的内存是有限的,现在的手机通常最大的内存使用为256M,目前还没发现Android中一个应用的最大内存分配超过256M的(经测试华为手机的最大内存是385M)

相关API:

java bitmap是什么,Android Bitmap 内存以及OOM问题讨论

ActivityManager.getMemoryClass(),首先获取系统服务中的ActivityManager

java bitmap是什么,Android Bitmap 内存以及OOM问题讨论

如下:

(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 究竟占多大内存

最近在做一款塔防游戏,用的事surfaceview框架,由于图片过多,而且游戏过程中都需要这些图片,所以加载成bitmap后造成OOM(outofmemory)异常。下面是我一步一步找解决此问题的纪录,再此分享,希望对以后出现此问题的开发者有所帮助。第一:出现问题,我的测试手机是2。2android操作系统,不会出现oom问题,但是在老板的android4.2上却出现了问题,因为是oom,所以我首先想到的是手动改变手机的内存大小限制。网上有些帖子说可以通过函数设置应用的HEAPSIZE来解决这个问题,其实是不对的。VMRuntime.getRuntime().setMinimumHeapSize(NewSize);堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。MaxHeapSize,是堆内存的上限值,Android的缺省值是16M(某些机型是24M),对于普通应用这是不能改的。函数setMinimumHeapSize其实只是改变了堆的下限值,它可以防止过于频繁的堆内存分配,当设置最小堆内存大小超过上限值时仍然采用堆的上限值,对于内存不足没什么作用。setTargetHeapUtilization(floatnewTarget)可以设定内存利用率的百分比,当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。在手机上进行了多次测试,确实不好使,在此,我断了改变内存限制的方法。第二:查找出现问题的原因。1,在网上搜索bitmap内存溢出,找到很多说是因为图片大小引起的此问题。观察我的资源文件,没有太大的图片,只是图片数量过多,有将近900张,分别找出一张最大的图片和几张比较大的图片,单独测试,没有发现问题。方法1排除。2,既然图片数量过多,突破点可能就是图片数量问题。于是分别找了200,400,600图片进行测试,在500左右的时候遇到错误,通过宝哥知道了将小图片整合存放到一张大图的方法,以此来减少图片的数量,但是仔细想想,加载成bitmap的时候还是要切割成小图生成bitmap,所以对此方法表示怀疑。由于以前没用过此方法,试试也无妨。所用到的工具是gdx—texturepackger,它只是一个工具,这里就不多说了。测试的最终结果是还是oom。方法2排除。3,现在看来,既然不是图片数量的问题,而且会在500张左右的时候报错,那就可能是占用内存大小的问题了,Android手机有内存限制,但是我的图片大小又大于这个限制,这让我头疼了很长时间,研究国外的一些文章,从中发现了一些有用的信息,这些信息能够加深你对Android的解析bitmap机制的理解,在此分享:AsofHoneycombBitmapdataisallocatedintheVMheap.作为蜂窝位图数据是在VM分配堆。)ThereisareferencetoitintheVMheap(whichissmall),buttheactualdataisallocatedintheNativeheapbytheunderlyingSkiagraphicslibrary.有一个引用在VM堆(小),但实际的数据是在本机堆分配由底层Skia图形库。Unfortunately,whilethedefinitionofBitmapFactory.decode…()saysthatitreturnsnulliftheimagedatacouldnotbedecoded,theSkiaimplementation(orrathertheJNIgluebetweentheJavacodeandSkia)logsthemessageyou’reseeing(“VMwon’tletusallocatexxxxbytes”)andthenthrowsanOutOfMemoryexceptionwiththemisleadingmessage“bitmapsizeexceedsVMbudget”.不幸的是,虽然BitmapFactory.decode的定义…()表示,它返回null如果图像数据不能解码,Skia实现(或者说JNI胶之间的Java代码和Skia)日志消息你看到(“VM不会让我们分配xxxx字节”),然后抛出一个OutOfMemory异常与误导信息”位图的大小超过VM预算”。TheissueisnotintheVMheapbutisratherintheNativeheap.这个问题不是在VM堆而是在本机堆。TheNatïveheapissharedbetweenrunningapplications,sotheamountoffreespacedependsonwhatotherapplicationsarerunningandtheirbitmapusage.本机堆是正在运行的应用程序之间共享,因此空闲空间的大小取决于其他运行程序,他们使用的位图。However,IhavefoundthatgetNativeHeapFreeSize()andgetNativeHeapSize()arenotreliable.然而,我发现getNativeHeapFreeSize()和getNativeHeapSize()是不可靠的。TheNativeheapsizevariesbyplatform.本机堆大小不同的平台。Soatstartup,wecheckthemaximumallowedVMheapsizetodeterminethemaximumallowedNativeheapsize.所以在启动时,我们检查最大允许VM堆大小来确定最大允许本机堆大小。“BitmapdataisnotallocatedintheVMheap”—itisallocatedontheVMheapasofHoneycomb“位图数据不是在VM分配堆”——这是VM分配的堆在蜂窝Yes.是的。AsofHoneycomb(v3.0),bitmapdataisallocatedontheVMheap.作为蜂窝(v3.0),位图数据堆上分配VM。SoalloftheaboveonlyappliestoGingerbread(v2.3.x)andbefore所以所有上述只适用于姜饼(v23x)和之前这些信息零零散散,但是不难发现,问题的原因就在于根据Android版本的不同,bitmapdata存放的位置是不同的,3.0以前是分配在nativeheap上,3.0以后是分配在VMheap上。

android bitmap 使用时候注意什么

一、问题的背景和意义

在Android移动应用开发中,对Bitmap的不小心处理,很容易引起程序内存空间耗尽而导致的程序崩溃问题。比如我们常遇到的问题:

java.lang.OutofMemoryError: bitmap size exceeds VM budget.

导致该问题的出现,一般由以下几方面原因导致:

引动设备一般存储空间非常有限。当然不同设备分配给应用的内存空间是不同的。但相对不但提高的设备分辨率而言,内存的分配仍然是相对紧张的。

Bitmap对象常常占用大量的内存空间,比如:对于2592*1936的设备,如果采用ARGB_8888的格式加载图像,内存占用将达到19MB空间。

在Anroid App中经常用到ListView,ViewPager等控件,这些控件常会包含较大数量的图片资源。

二、问题及场景分析

1高效地加载大图片。

BitmapFactory类提供了一些加载图片的方法:decodeByteArray(), decodeFile(), decodeResource(),等等。

为了避免占用较大内存,经常使用BitmapFactory.Options类,设置inJustDecodeBounds属性为true。

//

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

options.inJustDecodeBounds=true;

BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

为了避免java.lang.OutOfMemory的异常,我们在真正decode图片之前检查它的尺寸,除非你确定这个数据源提供了准确无误的图片且不会导致占用过多的内存。

加载一个按比例缩小的版本到内存中。例如,如果把一个原图是1024*768 pixel的图片显示到ImageView为128*96 pixel的缩略图就没有必要把整张图片都加载到内存中。为了告诉解码器去加载一个较小的图片到内存,需要在你的BitmapFactory.Options中设置 inSampleSize为true。例如,一个分辨率为2048x1536的图片,如果设置inSampleSize为4,那么会产出一个大概为512x384的图片。加载这张小的图片仅仅使用大概0.75MB,如果是加载全图那么大概要花费12MB(假设bitmap的配置是ARGB_8888).

2不要在主线程处理图片。

众所周知的问题,不再赘述。

注意两点:1.为了保证使用的资源能被回收,建议使用WeakReference,以应用内存内存紧张时,回收部分资源,保证程序进程不被杀死。

2.避免异步任务的长时间耗时操作,在任务执行结束后,及时释放资源。

3管理Bitmap内存。

在Android开发中,加载一个图片到界面很容易,但如果一次加载大量图片就复杂多了。在很多情况下(比如:ListView,GridView或ViewPager),能够滚动的组件需要加载的图片几乎是无限多的。

有些组件的child view在不显示时会回收,并循环使用,如果没有任何对bitmap的持久引用的话,垃圾回收器会释放你加载的bitmap。这没什么问题,但当这些图片再次显示的时候,要想避免重复处理这些图片,从而达到加载流畅的效果,就要使用内存缓存和本地缓存了,这些缓存可以让你快速加载处理过的图片。

3.1内存缓存

内存缓存以牺牲内存的代价,带来快速的图片访问。LruCache类(API Level 4之前可以使用Support Library)非常适合图片缓存任务,在一个LinkedHashMap中保存着对Bitmap的强引用,当缓存数量超过容器容量时,删除最近最少使用的成员(LRU)。

注意:在过去,非常流行用SoftReference或WeakReference来实现图片的内存缓存,但现在不再推荐使用这个方法了。因为从Android 2.3(API Level 9)之后,垃圾回收器会更积极的回收soft/weak的引用,这将导致使用soft/weak引用的缓存几乎没有缓存效果。顺带一提,在Android3.0(API Level 11)以前,bitmap是储存在native内存中的,所以系统以不可预见的方式来释放bitmap,这可能会导致短时间超过内存限制从而造成崩溃。收起

如果你还想了解更多这方面的信息,记得收藏关注本站。

java数据结构和算法 是什么?什么是数据结构和算法 java里data是什么意思,java 编程问题date.toString() 和 date() 有什么区别