OutofMemoryError:位图大小超过VM预算(Android)

时间:2009-10-19 02:13:35

标签: android exception bitmap dalvik

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

ERROR/AndroidRuntime(7906): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

ERROR/AndroidRuntime(7906):     at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:295)

我的代码很简单。我定义了一个带有默认图像的XML布局。我尝试在SD卡上加载一个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 我只是不知道它为什么不起作用。任何帮助都会很棒!谢谢,

克里斯。

9 个答案:

答案 0 :(得分:13)

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或简单的固定大小以减少内存消耗似乎更好地工作。

答案 1 :(得分:5)

请参阅此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;
}

答案 2 :(得分:4)

我最后使用以下代码调整了位图大小,这似乎解决了这个问题。

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

答案 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 :(");
}

答案 4 :(得分:4)

答案 5 :(得分:1)

我认为它是 - 它说它是什么。您的图像太大,因为当内存耗尽时它会在流中加载,因此抛出异常。这甚至不是你整体记忆的数量,而是你的特定活动有多少。

答案 6 :(得分:1)

在decodefile中使用这些选项。希望你能说明位图超出预算问题..

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]; 

答案 7 :(得分:0)

您检查过DDMS吗? 根据我遇到的情况,它可能不是图像的大小,因为Android似乎很好地处理大图像。 如果使用DDMS跟踪堆,您可能会发现您碰巧有大量可用内存。 您可以通过添加此

来“扩展”堆
static { @SuppressWarnings("unused")
byte dummy[] = new byte[ 8*1024*1024 ]; }    

到您的代码,强制堆扩展。它可能会减少频率。 不幸的是,除了它之外,它声称它不能分配一些字节数。说1M。如果您查看“免费”行,您会看到最大的块是>> 1M。 那里有一些奇怪的东西,我无法弄明白。它与扫描图像的速度无关。 我在某个帖子中看到你可以为bitmaps调用“recycle”左右。如果堆大小超过所采用的大小,我仍然不明白为什么它应该有用。

答案 8 :(得分:0)

当我开始将图像从320x240调整为类似64x240(缩小)时,我收到此错误,然后导入到我的项目中(因为我想提高渲染速度并且它包含许多无用的alpha区域,直到这一点)

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

  

你可以通过添加静态{@SuppressWarnings(“unused”)字节dummy [] = new byte [8 * 1024 * 1024]来“扩展”你的堆。 }   到你的代码,强制堆扩展。它可能会少一些   频繁。

我认为这就是发生在我身上的事。 Android会自动将drawables解码为位图,然后在编译时将所有内容都存储在堆上?

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

它必须像Marve所说的那样:在缩小我的drawable / image并将其导入我的项目之后,Heap在我的情况下还不够大。

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