2009-10-19 35 views
22

Nhận ngoại lệ trong BitmapFactory. Bạn không chắc chắn vấn đề là gì. (Tôi có thể đoán được vấn đề, nhưng không chắc tại sao nó lại xảy ra)OutofMemoryError: kích thước bitmap vượt quá ngân sách VM (Android)

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

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

Mã của tôi khá thẳng về phía trước. Tôi đã định nghĩa một bố cục XML với một hình ảnh mặc định. Tôi cố gắng tải một bm trên SDCard (nếu có - nó là). Nếu không, nó sẽ hiển thị hình ảnh mặc định. Dù sao .. Đây là mã số:

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) { 

Nó thất bại trên bm=Bitmap.createScaledBitmap bất kỳ suy nghĩ nào? Tôi đã làm một số nghiên cứu trên các diễn đàn, và nó chỉ đến this post Tôi chỉ không biết tại sao nó không hoạt động. Bất kỳ sự trợ giúp nào đều sẽ là tuyệt vời! Cảm ơn,

Chris.

+0

thế lớn là JPG hình ảnh ban đầu? Có một số báo cáo về loại lỗi này với hai tệp 6 Mpx tại đây: http://groups.google.com/group/android-developers/browse_thread/thread/0a6279680d1bd15e – schnaader

Trả lời

1

Tôi nghĩ đó là - nó nói gì. Hình ảnh của bạn quá lớn và vì nó được tải trong luồng khi bộ nhớ hết, ngoại lệ được ném. Nó thậm chí không phải là câu hỏi về số lượng bộ nhớ bạn có tổng thể nhưng bao nhiêu hoạt động cụ thể của bạn đã có sẵn.

+0

Hình ảnh từ máy ảnh điện thoại G1. Kích thước hình ảnh là 2048x1536 apx 1.01MB – Chrispix

+0

Đó là shoulf được OK nhưng sau đó, một lần nữa - nó không phải là bộ nhớ tích lũy mà đếm bao nhiêu đã được phân bổ bởi hệ thống cho nhiệm vụ cụ thể của bạn. Bạn có thể xác minh rằng mã của bạn hoạt động với nội dung 500K hoặc 50K không? – Bostone

4

Tôi đã thay đổi kích thước bitmap bằng cách sử dụng mã sau có vẻ như đã giải quyết được vấn đề.

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

Đảm bảo bảo vệ việc tạo bitmap của bạn không bị lỗi bộ nhớ! Với hầu hết các nền tảng, android không có nhiều bộ nhớ để chơi cùng và nó chạy nhanh với bitmap. Ngoài ra, hãy nhớ tự tái chế các bitmap của bạn càng nhiều càng tốt, tôi nhận thấy rằng bộ sưu tập rác có thể khá chậm.

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 :("); 
} 
+0

Cách tốt nhất để thực hiện GC? myFragileBitmap = null? – Chrispix

+0

Không phải lúc nào cũng có vẻ như vậy, vì một lý do nào đó tôi thường đặt nó thành null sau khi tái chế ... Tuy nhiên, tôi cho rằng có tồn tại một số ma thuật để xóa bitmap ... – Ralphleon

13

inSampleSize là một gợi ý hay. Nhưng một giá trị cố định thường không hoạt động tốt, vì các bitmap lớn từ các tệp thường là các tệp người dùng, có thể thay đổi từ hình thu nhỏ nhỏ đến hình ảnh 12MP từ máy ảnh.

Đây là thói quen tải nhanh và bẩn. Tôi biết có chỗ để cải thiện, giống như một vòng lặp mã hóa đẹp hơn, sử dụng quyền hạn của 2 để giải mã nhanh hơn, v.v. Nhưng đó là một sự khởi đầu làm việc ...

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

Btw, trong API mới hơn cũng có rất nhiều BitmapFactory.Option cho phù hợp hình ảnh để sàng lọc Sở KHĐT, nhưng tôi không chắc chắn cho dù họ thực sự đơn giản hóa mọi thứ. Sử dụng android.util.DisplayMetrics.density hoặc đơn giản là kích thước cố định để tiêu thụ ít bộ nhớ hơn dường như hoạt động tốt hơn.

0

Bạn đã kiểm tra DDMS chưa? Với những gì tôi đã gặp phải, nó có lẽ không phải là kích thước của hình ảnh, bởi vì Android dường như xử lý hình ảnh lớn khá tốt. Nếu bạn theo dõi đống bằng DDMS, bạn có thể thấy rằng bạn có rất nhiều bộ nhớ trống. Bạn có thể "mở rộng" đống của bạn bằng cách thêm này

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

mã của bạn, để buộc các đống để mở rộng. Nó có thể làm cho nó một chút ít thường xuyên hơn. Thật không may, với ngoại lệ, nó tuyên bố rằng nó không thể cấp phát một số lượng byte. Nói 1 triệu. Nếu bạn nhìn vào dòng "miễn phí", bạn sẽ thấy khối lớn nhất là >> 1M. Có điều gì đó kỳ lạ ở đó mà tôi không thể tìm ra. Nó không liên quan thậm chí với tốc độ của hình ảnh swiping. Tôi thấy trong một số chủ đề mà bạn có thể gọi là "tái chế" hoặc như vậy cho bitmap. Tôi vẫn không thấy lý do tại sao nó sẽ giúp đỡ nếu kích thước heap là cách trên kích thước lấy.

1

sử dụng các tùy chọn trong decodefile. hy vọng u có thể elemenate bitmap vượt quá vấn đề ngân sách vm ..

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

Phương pháp này đã giúp đỡ, cảm ơn bạn thân! : D – Xarialon

0

Tôi đã nhận lỗi này khi tôi bắt đầu thay đổi kích thước hình ảnh từ 320x240 đến một cái gì đó giống như 64x240 (thu hẹp), sau đó nhập vào dự án của tôi (kể từ khi tôi muốn cải thiện tốc độ dựng hình và nó chứa rất nhiều vùng alpha vô dụng cho đến thời điểm này).

nay là câu trả lời cuối cùng làm cho nhiều ý nghĩa:

You can "expand" your heap by adding this static { @SuppressWarnings("unused") byte dummy[] = new byte[ 8*1024*1024 ]; } to your code, to force the heap to expand. It may make it a bit less frequent.

Tôi nghĩ rằng đây là những gì xảy ra với tôi. Android tự động giải mã drawables vào bitmap, (và sau đó được lưu trữ trên một đống, tất cả trên thời gian biên dịch?)

tôi bắt đầu thấy lỗi, khi tôi sử dụng phiên bản nhỏ hơn của hình ảnh trong thời gian chạy (i mở rộng chúng trên thời gian chạy kể từ khi tôi lập trình một trò chơi VGA với đồ họa retro, sử dụng BitmapFactory.decodeResource và Bitmap.createScaledBitmap).

nó phải giống như Marve đã nói: Heap không đủ lớn trong trường hợp của tôi sau khi thu hẹp hình ảnh/hình ảnh có thể vẽ và nhập nó vào dự án của tôi.

Tôi đã có thể loại bỏ OutOfMemoryException của mình khi thay đổi kích thước hình ảnh trở lại kích thước lớn hơn (320x240), xác minh vấn đề tôi đoán?

5

Với tham chiếu đến link này, xin lưu ý các lỗi outOfMemory có thể được giải quyết bằng cách sau:

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; 
} 
Các vấn đề liên quan