内存溢出错误:位图大小超出VM预算 - Android

68

可能是重复问题:
Android:在将图像加载到位图对象时出现奇怪的内存不足问题

我正在从 URL 下载图片并将它们显示出来。在下载时,出现了“out of memory error : bitmap size exceeds VM budget”的错误。我正在使用 drawable。下面是代码:

HttpClient httpclient= new DefaultHttpClient();
HttpResponse response=(HttpResponse)httpclient.execute(httpRequest);
HttpEntity entity= response.getEntity();
BufferedHttpEntity bufHttpEntity=new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();

Bitmap bm = BitmapFactory.decodeStream(instream);
Bitmap useThisBitmap = 
Bitmap.createScaledBitmap(bm,bm.getWidth(),bm.getHeight(), true);
bm.recycle();
BitmapDrawable bt= new BitmapDrawable(useThisBitmap);
System.gc();

以下是错误信息:

`05-28 14:55:47.251: ERROR/AndroidRuntime(4188): 
 java.lang.OutOfMemoryError: bitmap size exceeds VM budget`

如果图像非常大,这个解决方案应该会有所帮助。 https://dev59.com/puo6XIcBkEYKwwoYTzNK#823966 - Fedor
我知道我有点晚了,但是如果在生成图像并创建它的时候 (img = Bitmap.createBitmap(size.x, size.y, Bitmap.Config.ARGB_8888);) 它会崩溃怎么办? - Manuel
@dragon112 在尝试创建位图之前,您可以检查可用内存-根据位图的大小,应该检查是否有足够的内存进行分配。但要注意:在API级别11之前,位图是在本地堆上分配的(使用“Debug”类调用给出可用本地堆等方法),从API级别11开始,位图完全在VM堆上分配。使用Runtime.getRuntime()的方法来检查可用的VM堆。 - AgentKnopf
有两个原因导致这个问题:本地图片太大或远程图片太大。在第一种情况下,需要手动调整大小。如果你从某个服务器获取图片,则需要在代码中调整图片大小。 - sandalone
当您在创建新的createScaledBitmap后调用bitmap.recycle时,要确保要回收的位图对象不是刚刚获取的那个对象。Android文档中指出:如果指定的宽度和高度与源位图的当前宽度和高度相同,则返回源位图,并且不会创建新的位图。 - philipp
显示剩余3条评论
7个回答

32

使用decodeStream(is, outPadding, opts)

BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inDither=false;                     //Disable Dithering mode
opts.inPurgeable=true;                   //Tell to gc that whether it needs free memory, the Bitmap can be cleared
opts.inInputShareable=true;              //Which kind of reference will be used to recover the Bitmap data after being clear, when it will be used in the future
opts.inTempStorage=new byte[32 * 1024]; 

谢谢,我的应用程序现在可以工作了! - jucajl
2
谢谢,我已经寻找解决方案好几个月了。 - sanjeev

6
你可以检查图片大小,然后通过适当的因子对其进行降采样。
请参见此问题:处理大位图

2
这个问题似乎已经被多次报告,例如这里这里...
抱歉Shalini,如果是同一个问题,似乎根本没有解决方案...
唯一的建议是Romain Guy提出的减少内存使用量...
所以,祝你好运,想出不同的解决方案...

3
有一个解决方案:使用比最大允许值更少的内存。我知道这个回答可能令人沮丧,但手机没有像台式机那样拥有“无限”的RAM。你必须小心谨慎。 - Romain Guy
不知道你在Stack上也会出现 ;) 就像我说的,你的建议是使用更少的内存... 你会建议做什么来实现这个目标?减小图片的尺寸吗? - Sephy
@RomainGuy 顺便说一句,现在已经是2020年了,我的手机有4GB的RAM。 - user253751

1

0

事实是,一些Android版本存在漏洞,尤其是2.1版本总是出现此类问题。

我发布了一个应用程序,在资源使用方面非常小心谨慎。我甚至删除了很多位图并且现在它们通过图形原语动态创建。当不使用它们时,我还会回收这些位图。当然,我已经检查过我的应用程序是否存在内存泄漏:使用的内存不会无限增长,始终保持在合理的范围内。

尽管我已经花了很多功夫来避免这个问题,但我仍然会在2.1和2.1-update1设备上遇到许多恼人的异常情况。我现在正在使用critercism报告崩溃,并且我已经发现即使应用程序只使用4兆字节的RAM,它也会发生崩溃,比每个Android设备必须拥有16M堆大小要少四倍 -而事实上大多数设备现在的堆大小都大于16M-。

我所有的位图都有800x480像素的大小,即使最坏情况下使用ARGB_8888格式也不会占用超过1.5MB的空间,但是当只占用4兆字节时尝试加载一个位图时程序会崩溃,因此至少还应该有12MB的空闲空间。我的大多数位图都以ARGB_4444格式加载,这种格式只占用一半的内存,只有在位图看起来非常糟糕时才使用ARGB_8888。

所以对我来说很明显,在这些Android版本中有一些问题没有得到很好的解决。99.9%的崩溃来自2.1和2.1-update版本,其余可能由其他特定原因解释。


0

我尝试了很多方法,这是有效的。

BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inDither=false;                     //Disable Dithering mode
opts.inPurgeable=true;        
opts.inScale=8;
///after you use your images
System.gc();

1
请求垃圾回收并不能清除内存泄漏问题。 - Christopher Perry

-2

这是一个实用的答案,我试图在运行时避免这个问题。它也解决了我的问题。

Runtime.getRuntime().gc();

调用垃圾回收器是一个好主意。


6
这并没有明确调用垃圾回收器,但是建议虚拟机执行此操作。 - caw
如果你的内存泄漏了,这个操作将毫无作用。垃圾回收只会回收那些没有其他引用指向它们的对象。 - Christopher Perry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接