代码之家  ›  专栏  ›  技术社区  ›  Chrispix

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

  •  22
  • Chrispix  · 技术社区  · 15 年前

    在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 回复  |  直到 9 年前
        2
  •  13
  •   M. Schenk    15 年前

    注射是一个很好的提示。但固定值通常不起作用,因为文件中的大位图通常是用户文件,从微小的缩略图到数字图像中的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中也有很多位图工厂。选项是为了使图像适合屏幕dpi,但我不确定它们是否真的简化了任何东西。使用android.util.displaymetrics.density或简单地使用固定大小以减少内存消耗似乎效果更好。

        3
  •  5
  •   Danny Beckett    12 年前

    关于这个 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;
    }
    
        4
  •  4
  •   Ralphleon    15 年前

    确保避免内存不足错误创建位图!在大多数平台上,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 :(");
    }
    
        5
  •  4
  •   mrucci Bernhard Zürn    14 年前

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

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inSampleSize = 8;
    Bitmap preview_bitmap = BitmapFactory.decodeFile(mPathName, options);
    
        6
  •  1
  •   Bostone    15 年前

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

        7
  •  1
  •   Akshay    12 年前

    在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]; 
    
        8
  •  0
  •   dcharles    13 年前

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

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

    到您的代码,强制堆展开。这可能会降低频率。 不幸的是,除了这个例外,它声称它不能分配一些字节。假设1米。如果你看一下“免费”行,你会发现最大的块是1米。 有件奇怪的事我想不出来。它甚至与刷卡图像的速度无关。 我在一些线程中看到,对于位图,您可以称之为“回收”。我仍然不明白如果堆的大小远远高于所取的大小,为什么它会有帮助。

        9
  •  0
  •   calav3ra    13 年前

    当我开始将一个图像的大小从320x240调整为64x240(缩小),然后导入到我的项目中(因为我想提高渲染速度,在这之前它包含很多无用的alpha区域)。

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

    您可以通过添加这个静态@SuppressWarnings(“unused”)字节dummy[]=new byte[8*1024*1024]; 到您的代码,强制堆展开。可能会让它少一点 频繁。

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

    当我在运行时使用图像的较小版本时,我开始看到这个错误(我在运行时使用BitmapFactory.DecodeResource和Bitmap.CreateScalledBitmap在运行时对它们进行缩放,因为我用怀旧图形编写了一个VGA游戏)。

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

    当我将图像重新调整到更大的尺寸(320x240)时,我能够消除内存不足的异常,这验证了我猜想的问题吗?