【问题标题】:OutofMemoryError: bitmap size exceeds VM budget (Android)OutofMemoryError:位图大小超出 VM 预算(Android)
【发布时间】:2010-12-07 21:15:01
【问题描述】:

在 BitmapFactory 中获取异常。不确定是什么问题。 (嗯,我可以猜到这个问题,但不知道为什么会发生)

ERROR/AndroidRuntime(7906): java.lang.OutOfMemoryError: 位图大小超出 VM 预算

错误/AndroidRuntime(7906):在 android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:295)

我的代码非常简单。我定义了一个带有默认图像的 XML 布局。我尝试在 SDCard 上加载 bm(如果存在 - 它是)。如果不是,则显示默认图像。无论如何..这是代码:

public class showpicture extends Activity {
  public void onCreate(Bundle savedInstanceState) {

         /** Remove menu/status bar **/
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         final Window win = getWindow();   
         win.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);

            Bitmap bm;
         super.onCreate(savedInstanceState);
         setContentView(R.layout.showpicture);
            try {
         ImageView mImageButton = (ImageView)findViewById(R.id.displayPicture);
         bm = Bitmap.createScaledBitmap(BitmapFactory.decodeFile("/sdcard/dcim/Camera/20091018203339743.jpg"),100, 100, true);
         parkImageButton.setImageBitmap(bm);
         }
         catch (IllegalArgumentException ex) {
          Log.d("MYAPP",ex.getMessage());
         } 
            catch (IllegalStateException ex) {

bm=Bitmap.createScaledBitmap 失败有什么想法吗?我在论坛上做了一些研究,它指向this post 我只是不知道为什么它不起作用。任何帮助都会很棒!谢谢,

克里斯。

【问题讨论】:

标签: android exception bitmap dalvik


【解决方案1】:

inSampleSize 是一个很好的提示。但固定值通常不能正常工作,因为文件中的大位图通常是用户文件,从微小的缩略图到相机中的 12MP 图像不等。

这是一个快速而肮脏的加载程序。我知道还有改进的余地,比如更好的编码循环,使用 2 的幂来更快地解码,等等。但这是一个工作的开始......

public static Bitmap loadResizedBitmap( String filename, int width, int height, boolean exact ) {
    Bitmap bitmap = null;
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile( filename, options );
    if ( options.outHeight > 0 && options.outWidth > 0 ) {
        options.inJustDecodeBounds = false;
        options.inSampleSize = 2;
        while (    options.outWidth  / options.inSampleSize > width
                && options.outHeight / options.inSampleSize > height ) {
            options.inSampleSize++;
        }
        options.inSampleSize--;

        bitmap = BitmapFactory.decodeFile( filename, options );
        if ( bitmap != null && exact ) {
            bitmap = Bitmap.createScaledBitmap( bitmap, width, height, false );
        }
    }
    return bitmap;
}

顺便说一句,在较新的 API 中,还有很多 BitmapFactory.Option 用于将图像拟合到屏幕 DPI,但我不确定它们是否真的简化了任何事情。恕我直言,使用 android.util.DisplayMetrics.density 或简单地使用固定大小来减少内存消耗似乎效果更好。

【讨论】:

    【解决方案2】:

    参考这个link,请注意outOfMemory错误可以通过以下方式解决:

    public Bitmap decodeFile(String filePath) {
    
    Bitmap bitmap = null;
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inPurgeable = true;
    
    try {
    BitmapFactory.Options.class.getField("inNativeAlloc").setBoolean(options,true);
    
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
    
    if(filePath != null)
    {
        bitmap = BitmapFactory.decodeFile(filePath, options);               
    }
    
    return bitmap;
    }
    

    【讨论】:

      【解决方案3】:

      【讨论】:

      • 我讨厌只是链接的答案。不要误会我的意思,链接很好,但不解释就直接显示链接确实感觉很懒。
      【解决方案4】:

      确保防止您的位图创建出现内存不足错误!在大多数平台上,android 没有太多内存可供使用,并且使用位图会很快耗尽。另外,请确保尽可能手动回收位图,我注意到垃圾收集可能相当慢。

      try{            
        Bitmap myFragileBitmap = Bitmap.createBitmap(500, 500, Bitmap.Config.ARGB_8888);
      }
      catch(IllegalArgumentException e){
        Log.e(TAG,"Illegal argument exception.");
      }
      catch(OutOfMemoryError e){
        Log.e(TAG,"Out of memory error :(");
      }
      

      【讨论】:

      • 最好的 GC 方法? myFragileBitmap=null?
      • 似乎并不总是这样做,由于某种原因,我通常在回收后将其设置为 null ......我认为存在一些用于位图清除的skia 魔法......
      【解决方案5】:

      我最终使用以下似乎解决了问题的代码调整了位图的大小。

      BitmapFactory.Options options = new BitmapFactory.Options();
      options.inSampleSize = 8;
      Bitmap preview_bitmap = BitmapFactory.decodeFile(mPathName, options);
      

      【讨论】:

        【解决方案6】:

        我认为它是 - 它说它是什么。您的图像太大,因为它是在内存耗尽时加载到流中的,所以会引发异常。这甚至不是关于你有多少内存的问题,而是你的特定活动有多少可用的问题。

        【讨论】:

        • 图片来自G1手机摄像头。图片大小为 2048x1536 像素 1.01MB
        • 这应该没问题,但是再一次 - 重要的不是累积内存,而是系统为您的特定任务分配了多少内存。您能否验证您的代码是否适用于 500K 或 50K?
        【解决方案7】:

        在解码文件中使用这些选项。希望你能元素位图超出虚拟机预算问题..

        BitmapFactory.Options bfOptions=new BitmapFactory.Options(); 
        
        bfOptions.inDither=false;          //Disable Dithering mode
        bfOptions.inPurgeable=true;       //Tell to gc that whether it needs free memory, the Bitmap can be cleared
        bfOptions.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
        bfOptions.inTempStorage=new byte[32 * 1024]; 
        

        【讨论】:

          【解决方案8】:

          您检查过 DDMS 吗? 就我遇到的情况而言,这可能不是图像的大小,因为 Android 似乎可以很好地处理大图像。 如果您使用 DDMS 跟踪堆,您可能会发现您碰巧有很多可用内存。 你可以通过添加这个来“扩展”你的堆

          static { @SuppressWarnings("unused")
          byte dummy[] = new byte[ 8*1024*1024 ]; }    
          

          到您的代码,强制堆扩展。它可能会降低它的频率。 不幸的是,除了它声称它不能分配一定数量的字节之外。说1M。如果你看一下“free”行,你会看到最大的块是 >> 1M。 那里有一些奇怪的东西,我无法弄清楚。它甚至与滑动图像的速度无关。 我在一些线程中看到您可以为位图调用“回收”左右。我仍然不明白如果堆大小远高于所采用的大小,为什么会有帮助。

          【讨论】:

            【解决方案9】:

            当我开始将图像的大小从 320x240 调整为 64x240(缩小),然后导入到我的项目中时出现此错误(因为我想提高渲染速度,并且在此之前它包含许多无用的 alpha 区域) .

            现在最后一个答案很有意义:

            你可以通过添加这个 static { @SuppressWarnings("unused") byte dummy[] = new byte[ 8*1024*1024 ]; 来“扩展”你的堆。 } 到您的代码中,以强制堆扩展。它可能会减少一点 经常。

            我想这就是发生在我身上的事。 Android 会自动将可绘制对象解码为位图,(然后存储在堆中,全部在编译时进行?)

            当我在运行时使用较小版本的图像时,我开始看到错误(我在运行时放大了它们,因为我使用 BitmapFactory.decodeResource 和 Bitmap.createScaledBitmap 编写了带有复古图形的 VGA 游戏)。

            一定像 Marve 说的:在缩小我的可绘制/图像并将其导入我的项目后,堆在我的情况下不够大。

            将图像调整回更大尺寸 (320x240) 时,我能够摆脱 OutOfMemoryException,这验证了我猜的问题?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-02-25
              • 2011-12-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-08-19
              相关资源
              最近更新 更多