Android:BitmapFactory.decodeStream() 内存不足,400KB 文件,2MB 空闲堆
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11820266/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: BitmapFactory.decodeStream() out of memory with a 400KB file with 2MB free heap
提问by Mayank
My app is hitting an OOM error at the following line in the source:
我的应用程序在源代码中的以下行遇到 OOM 错误:
image = BitmapFactory.decodeStream(assetManager.open(imgFilename));
Just before the allocation that causes the app to be killed with an OOM error:
就在导致应用程序因 OOM 错误而被终止的分配之前:
(...)
08-05 21:22:12.443: I/dalvikvm-heap(2319): Clamp target GC heap from 25.056MB to 24.000MB
08-05 21:22:12.443: D/dalvikvm(2319): GC_FOR_MALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 58ms
08-05 21:22:14.513: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2709K/5379K, external 18296K/19336K, paused 101ms
08-05 21:22:14.903: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:14.903: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2709K/5379K, external 18312K/19336K, paused 53ms
08-05 21:22:22.843: D/ddm-heap(2319): Heap GC request
08-05 21:22:22.963: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:22:22.963: D/dalvikvm(2319): threadid=1: still suspended after undo (sc=1 dc=1)
08-05 21:22:22.963: D/dalvikvm(2319): GC_EXPLICIT freed 1K, 50% free 2710K/5379K, external 18312K/19336K, paused 116ms
DDMS reports a similar picture about the state of the heap:
DDMS 报告了有关堆状态的类似图片:
Heap Size: 5.254 MB
Allocated: 2.647 MB
Free: 2.607 MB
%Used: 50.38%
#Objects 49,028
Single stepping over this line results in an OOM error:
单步越过这条线会导致 OOM 错误:
08-05 21:26:04.783: D/dalvikvm(2319): GC_EXTERNAL_ALLOC freed <1K, 50% free 2710K/5379K, external 18312K/19336K, paused 57ms
08-05 21:26:05.023: E/dalvikvm-heap(2319): 2097152-byte external allocation too large for this process.
08-05 21:26:05.163: I/dalvikvm-heap(2319): Clamp target GC heap from 25.073MB to 24.000MB
08-05 21:26:05.163: E/GraphicsJNI(2319): VM won't let us allocate 2097152 bytes
08-05 21:26:05.163: D/dalvikvm(2319): GC_FOR_MALLOC freed 0K, 50% free 2710K/5379K, external 18312K/19336K, paused 30ms
08-05 21:26:05.283: D/skia(2319): --- decoder->decode returned false
- The size of the file referenced by "imgFileName" is reported to be < 400K on Windows. So why does BitmapFactory.decodeStream try to allocate 2MB?
- Why is there an OOM error when there seems to be enough free space?
- 在 Windows 上,“imgFileName”引用的文件大小被报告为 < 400K。那么为什么 BitmapFactory.decodeStream 尝试分配 2MB?
- 当似乎有足够的可用空间时,为什么会出现 OOM 错误?
This app is targeting Android 2.2 and up.
此应用面向 Android 2.2 及更高版本。
Thanks in advance!
提前致谢!
回答by Paulo Cheque
Android library is not so smart for loading images, so you have to create workarounds for this.
Android 库在加载图像方面并不是那么聪明,因此您必须为此创建解决方法。
In my tests, Drawable.createFromStream
uses more memory than BitmapFactory.decodeStream
.
在我的测试中,Drawable.createFromStream
使用的内存比BitmapFactory.decodeStream
.
You may change the Color scheme to reduce memory (RGB_565), but the image will lose quality too:
您可以更改配色方案以减少内存 (RGB_565),但图像也会降低质量:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
Reference: http://developer.android.com/reference/android/graphics/Bitmap.Config.html
参考:http: //developer.android.com/reference/android/graphics/Bitmap.Config.html
You can also load a scaled image, which will decrease a lot the memory usage, but you have to know your images to not lose too much quality of it.
您还可以加载缩放图像,这将大大减少内存使用量,但您必须了解您的图像不要失去太多质量。
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
Reference: http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html
参考:http: //developer.android.com/reference/android/graphics/BitmapFactory.Options.html
To define the inSampleSize dynamically, you may want to know the image size to take your decision:
要动态定义 inSampleSize,您可能想知道图像大小以做出决定:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bitmap = BitmapFactory.decodeStream(stream, null, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
options.inJustDecodeBounds = false;
// recreate the stream
// make some calculation to define inSampleSize
options.inSampleSize = ?;
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, options);
You can customize the inSampleSize according to the screen size of the device. To get the screen size, you can do:
您可以根据设备的屏幕尺寸自定义 inSampleSize。要获得屏幕尺寸,您可以执行以下操作:
DisplayMetrics metrics = new DisplayMetrics();
((Activity) activity).getWindowManager().getDefaultDisplay().getMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight =metrics.heightPixels;
Other tutorials: - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html- http://developer.android.com/training/displaying-bitmaps/index.html
其他教程: - http://developer.android.com/training/displaying-bitmaps/load-bitmap.html- http://developer.android.com/training/displaying-bitmaps/index.html
回答by Michell Bak
Please see this for a guide on loading large Bitmaps more efficiently:
有关更有效地加载大型位图的指南,请参阅此内容:
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
A 400 KB image file can easily take up 5-10 MB of RAM.
一个 400 KB 的图像文件很容易占用 5-10 MB 的 RAM。
回答by nEx.Software
The size of the file on disk doesn't necessarily coincide with the size of the file in memory. Chances are likely that the file is compressed, which they won't be when decoded. You need to account for that in your calculation.
磁盘上文件的大小不一定与内存中文件的大小一致。文件很可能被压缩,而解码时则不会。您需要在计算中考虑到这一点。
Multiply the size of the image (width x height) by the color depth of the image to get the in-memory size of the image.
将图像的大小(宽 x 高)乘以图像的颜色深度,得到图像的内存大小。
回答by yugidroid
Basically you can resolve your issue by trying to scale your Bitmap
and you'll see memory consumption reduced. To do it you can copy he method shown here.
基本上,您可以通过尝试扩展您的问题来解决您的问题,Bitmap
并且您会看到内存消耗减少。为此,您可以复制此处显示的方法。
Also, there is a dedicated page at Android Developeres that could help you understand better how to load large Bitmaps. Take a look at the official documentation.
此外,Android Developeres 上有一个专门的页面,可以帮助您更好地了解如何加载大型位图。看看官方文档。
回答by rishabh
While the above answers are obviously correct, a better practice is also to set explicitlythe ImageView's bitmap/src property to null, when they're no longer used, mostly when your activity is being destroyed. Any other heavy duty resources( large text, audio, video) etc. may also be nullified. This ensures that the resources are freed instantly, and not wait for the GC to collect.
虽然上述答案显然是正确的,但更好的做法是将 ImageView 的 bitmap/src 属性显式设置为null,当它们不再使用时,主要是在您的活动被销毁时。任何其他重型资源(大文本、音频、视频)等也可能被取消。这样可以确保立即释放资源,而不是等待 GC 收集。
回答by Siamak SiaSoft
You can try to assign the bitmap via Glidelibrary. Glide uses the most appropriate method (specific to your device and environment) to port the bitmap file into the graphical layer(ImageView).
您可以尝试通过Glide库分配位图。Glide 使用最合适的方法(特定于您的设备和环境)将位图文件移植到图形层(ImageView)中。
Nice and easy:
好,易于:
Glide.with(getContext())
.load(imageFile.getPath())
.into(previewImageView);
回答by Vaibhav Jain
I change the insample size by 2. My problem is resolved. But be sure that quality of image doesnt get destroy.
我将样本大小更改了 2。我的问题已解决。但请确保图像质量不会被破坏。
回答by varotariya vajsi
I resolved OutOfMemoryErrorissue using below method
我使用以下方法解决了OutOfMemoryError问题
private Bitmap downloadImageBitmap(String sUrl) {
this.url = sUrl;
bitmap = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
for (options.inSampleSize = 1; options.inSampleSize <= 32; options.inSampleSize++) {
InputStream inputStream = new URL(sUrl).openStream();
try {
bitmap = BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
break;
} catch (OutOfMemoryError outOfMemoryError) {
}
}
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}