Android 上的位图大小超出 VM 预算错误
我正在将 Asset 文件夹中的 100 张图像加载到数组对象中。图片非常小(每张 png ~20k),我使用这段代码对其进行处理,并防止内存泄漏和内存泄漏。优化性能:
循环:
// create resized bitmap from asset resource
InputStream istr = assetManager.open(pics[i]);
Bitmap b = BitmapFactory.decodeStream(istr);
b = Bitmap.createScaledBitmap(b, 240, 240, true);
其中 pics[i] 是位于我的资源文件夹中的文件名列表。
该代码适用于我,但我仍然不时收到来自用户的错误(我在开发人员控制台错误上看到它):
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
我可以做些什么来改进它?或者这是Android的世界,我们永远无法交付完美的应用程序?
I'm loading 100 images from Asset folder to an array object. The pictures are quite small (png ~20k each), and im using this code do to it, and to prevent memory leak & optimized performances:
in a loop:
// create resized bitmap from asset resource
InputStream istr = assetManager.open(pics[i]);
Bitmap b = BitmapFactory.decodeStream(istr);
b = Bitmap.createScaledBitmap(b, 240, 240, true);
where pics[i] is a list of filenames which sits in my Asset folder.
The code works for me, but i still receive from time to time Errors from users (i see it on Developer Console errors):
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
Is there anything i can do to improve it? or this is Android's world, we can never deliever a perfect application?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当然你可以改进一些:不要同时将太多图片加载到内存中(或减小它们的大小)。有些设备没有太多可用内存。您的设备的堆限制可能比某些客户的手机更高。因此,当它对你有用时,它就会崩溃(请参阅此视频了解一些堆限制[ 4:44])。
您可以通过
ActivityManager 获取可用堆大小。 getMemoryClass()
。为了改进这一点,请测试您现在需要哪些图片(哪些已显示),哪些不需要。仅加载所需的位图并回收不再需要的位图。
另请尝试使用 BitmapFactory.decodeResource() 和 BitmapFactory.Options.inSampleSize。这允许您直接以较低分辨率加载图像,而无需像此处那样以完整尺寸加载图像,然后调整它们的大小。
Of course you can improve something: Don't load too much pictures into the memory at the same time (or reduce their size). Some devices don't have much memory available. Your device may have a higher heap limit than some of your customers phones. Therefore it crashes for them when it works for you (see this video for some heap limits [at 4:44]).
You may get the available heap size via
ActivityManager.getMemoryClass()
.To improve this, test which pictures you need right now (which are displayed) and are which not. Load only the required ones and recycle the bitmaps you don't need anymore.
Also try using the
BitmapFactory.decodeResource()
andBitmapFactory.Options.inSampleSize
. This allows you to load images at a lower resolution directly without loading them at the full size and then resizing them as you did here.位图未压缩,因此它们存储在
width * height * 4
字节中。这意味着每个图像使用大约 225 KB 的内存。 100 张图像大约需要 22 MB 内存。最小堆大小为 16 MB,但设备通常具有 24+ MB 堆。而且这个堆不仅用于数据,还用于活动、视图等。这意味着您无法加载 100 个此大小的位图。Bitmaps aren't compressed so they are stored in
width * height * 4
bytes. It means that every image uses about 225 KB of memory. 100 images require about 22 MB of memory. The minimal heap size is 16 MB, but devices usually have 24+ MB heap. And this heap is used not only for data but also for activities, view and so on. That means you can't load 100 bitmaps of this size.根据经验,您应该只需要显示用户实际可以看到的内容。将其他任何内容(图形)保存在内存中只是锦上添花。这就是为什么具有更高分辨率屏幕的设备将具有更大的可用堆大小。
例如,在 320x480 屏幕上,您至少需要 320x480x4=614400 (600kb)。
考虑到这个概念,您需要考虑是否需要在内存中保存 100 个
Bitmap
。用户是否一次查看 100 个位图?在这种情况下,您可以降低图像质量,而不会降低用户体验(屏幕上只有这么多像素)。用户是否滚动浏览了 100 个位图?然后根据需要动态转储和加载图像(使用一些缓存以保证平滑度)。总有一个解决方法。
As a rule of thumb you should only ever need to show what the user can actually see. Holding anything else (graphics) in memory is just icing on the cake. This is why devices with higher resolution screens will have larger heap sizes available.
For example, on a 320x480 screen, you would only need as a minimum, 320x480x4=614400 (600kb).
Taking this concept into mind, you need to consider whether you need to hold 100
Bitmap
s in memory. Is the user looking at 100Bitmap
s at one time? In that case you can reduce the quality of the images without degrading the user experience (there are only so many pixels on the screen). Is the user scrolling through 100Bitmap
s? Then dump and load images dynamically as appropriate (with a bit of caching for smoothness).There is always a workaround.