位图图像内存不足

9
我知道有关 Android 位图图片内存不足的讨论很多,但我想知道有没有人能够向我解释一下...
目前在我的应用程序中,我有一个活动,列出了图像缩略图(低质量),当我点击一个图像时,它会打开一个新的活动以全屏查看图像。在我的第二个活动类中,我有以下代码:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
bm = BitmapFactory.decodeFile(myImagePath, options);

我将其放入ImageView中进行显示。这样可以完整地显示我的图像,质量很高。但是,如果我点击返回,然后再次点击查看该图像(并重复这个过程6次)...在第6次打开图像(activity2)时,我会收到一个内存不足错误,指出堆大小=6919KB,分配=3125KB,位图大小=25848KB!为什么位图大小会那么大?我认为可能一直在创建新的实例,所以我决定在第二个活动中添加一个方法,用于当按下返回键时...在这个方法中,我设置了我的位图=null,并执行了System.gc()来清除垃圾回收器,但这没有解决问题。我仍然在第6次点击缩略图以查看全分辨率图像时收到内存不足错误。有人能解释一下吗?谢谢

这大约是一个带有阿尔法通道的6百万像素位图。 位图很大。 - Steve-o
为什么位图大小会在内存不足错误时为25MB?正如我所说,它可以在5个视图上工作,并在第6次运行时耗尽内存。 - Mr X
我想我应该是吧..但我不明白怎么回事。 - Mr X
2个回答

16

这里有来自安卓的一些伟大信息,详细解释了所有问题,并介绍了如何解决这个问题这里.

每个像素是4个字节。6M像素=24MB。

一张照片可以使用完所有内存。

位图占用了大量内存,特别是对于像照片这样的富有图像。例如,Galaxy Nexus相机拍摄的照片高达2592x1936像素(500万像素)。如果使用的位图配置是ARGB_8888(从Android 2.3开始的默认设置),那么将该图像加载到内存中需要约19MB的内存(2592*1936*4个字节),立即耗尽某些设备上的每个应用程序限制。

我再次向您指出,我在另一个SO问题中发现了这个不错的链接,其中有关于如何正确克服这个问题的教程。


如何使用Picasso或Universal Image Loader解决这个问题?我正在使用这些库,但仍然很快遇到OOM。 - Sagar Panwala
@SagarPanwala 【这可能很有用】(https://dev59.com/6Yrda4cB1Zd3GeqPMGpP)。同时请注意,您还在其他地方使用了太多内存。【问题可能不在Picasso本身】(https://github.com/square/picasso/issues/1153) - IAmGroot
但是我在主屏幕上有这个要求,我只是运行应用程序并滚动它,然后它就崩溃了。我有一个viewpager,其中包含5个图像(宽度和高度=屏幕宽度),作为ListView项。 - Sagar Panwala
@SagarPanwala 你确定高度和宽度是屏幕宽度吗?确保只在需要时加载图像,并在不可见时处理它。最好提出自己的问题,附上详细信息/代码/图像,以便社区可以帮助 :) - IAmGroot

2

inSample size 应该设置为使图像缩放到显示区域的大小(1 = 全尺寸),除非您认为需要使用图像的所有位,因此2将等于1/2比例,4将等于1/4比例等。

在使用 =null 之前完成位图时,请尝试使用 bm.recycle()。

更新

查看第二个答案 recycle是什么意思,除非您已经尝试过并且它没有起作用。我已经使用加载图像做过类似的事情,并且从未耗尽内存,这并不能证明它适用于您,但据我所知,这是最佳实践。


你的图像硬件大小是否小于显示器尺寸,还是说你需要操作位?至于.recycle()什么也没做,这不是文档所说的 --- void recycle() 释放与此位图关联的本机对象,并清除对像素数据的引用。那么你真的尝试过.recycle()吗? - Idistic
3
回收(recycle)确实释放了Bitmap使用的内存,并且非常重要。 - David Snabel-Caunt
3
我已经修复了OOM异常。基本上,当销毁一个Activity时,Android不会进行垃圾回收。所以当你重新启动该Activity并加载位图图片时,内存堆栈会很快变大,并最终耗尽内存。为了解决这个问题,我在onDestory方法中加入了以下代码:bm.recycle; customImageView.setImageDrawable(null); System.gc(); - Mr X
@dronyx,是的,你需要在GC工作之前删除所有引用。当然,当你谈论应用程序上下文时,我假设你之前使用了一个未正确处理的活动上下文?下次可以提供更多代码,这样我们就可以看到所有内容。无论如何,很高兴现在它能正常工作了,不过仍建议使用.recycle来进行优化。 - Idistic
先生,它不一定要在OnDestory上,对吧?只要你完成了图像处理,它可以放在任何地方。 - Snake
显示剩余3条评论

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