从外部存储加载位图时出现OutOfMemory异常

Fix*_*int 17 android out-of-memory

在我的应用程序中,我从JPEG和PNG文件加载了几个图像.当我将所有这些文件放入assets目录并以这种方式加载时,一切正常:

InputStream stream = getAssets().open(path);
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, null);
stream.close();
return new BitmapDrawable(bitmap);
Run Code Online (Sandbox Code Playgroud)

但是当我尝试从SD卡加载完全相同的图像时,我得到一个OutOfMemory异常!

InputStream stream = new FileInputStream("/mnt/sdcard/mydata/" + path);
Bitmap bitmap = BitmapFactory.decodeStream(stream, null, null);
stream.close();
return new BitmapDrawable(bitmap);
Run Code Online (Sandbox Code Playgroud)

这是我在日志中得到的:

11-05 00:53:31.003: ERROR/dalvikvm-heap(13183): 827200-byte external allocation too large for this process.
11-05 00:53:31.003: ERROR/GraphicsJNI(13183): VM won't let us allocate 827200 bytes
...
11-05 00:53:31.053: ERROR/AndroidRuntime(13183): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
11-05 00:53:31.053: ERROR/AndroidRuntime(13183):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
...
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

更新:在真实设备上尝试了这两个 - 似乎我无法将超过12MB的位图加载到所谓的"外部存储器"(这不是SD卡).

100*_*abh 8

我尝试了这里提到的所有方法和其他资源,但我得出的结论是,设置ImageView对null的引用将解决问题:

  public Bitmap getimage(String path ,ImageView iv)
   {
    //iv is passed to set it null to remove it from external memory
    iv=null;
    InputStream stream = new FileInputStream("/mnt/sdcard/mydata/" + path);
    Bitmap bitmap = BitmapFactory.decodeStream(stream, null, null);
    stream.close();
    stream=null;
    return bitmap;
    }
Run Code Online (Sandbox Code Playgroud)

你完成了!

注意:虽然它可以解决上述问题,但我建议你检查Tom van Zummeren的优化图像加载.

并且还要检查 SoftReference:在VM将抛出OutOfMemoryError之前,保证指向软可访问对象的所有SoftReferences都被清除.


Ebo*_*ike 5

  • 使用位图做很多事情时,不要调试应用程序 - 只需运行它.调试器将留下内存泄漏.
  • 位图非常昂贵.如果可能,通过创建BitmapFactory.Options并设置inSampleSize为> 1来加载它们.

编辑:此外,请务必检查您的应用程序是否有内存泄漏.泄漏位图(使用static位图是一种很好的方法)会很快耗尽你的可用内存.


Reu*_*ton 4

您的 API 使用可能没有任何问题,我想我们所能做的就是推断使用 AssetManager 涉及的幕后堆分配比从 SD 卡打开随机文件要少。

800KB 对于任何人来说都是一个严重的分配...这无疑是用于解压缩的图像像素。既然您知道图像的大小,那么它的深度是多少?如果它是 32bpp,那么尝试使用 覆盖它inPreferredConfig