2009-10-19 10 views
22

Uzyskanie wyjątku w BitmapFactory. Nie jestem pewien, o co chodzi. (Mogę zgadnąć problem, ale nie jestem pewien, dlaczego tak się dzieje)OutofMemoryError: rozmiar bitmapy przekracza budżet maszyn wirtualnych (Android)

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

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

Mój kod jest dość prosty. Zdefiniowałem układ XML z domyślnym obrazem. Próbuję załadować plik bm na karcie SD (jeśli jest obecny - jest). Jeśli nie, pokazuje domyślny obraz. W każdym razie .. Oto kod:

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

To nie na bm=Bitmap.createScaledBitmap jakieś przemyślenia? Zrobiłem kilka badań na forach i wskazałem na this post Po prostu nie wiem, dlaczego to nie działa. Każda pomoc będzie świetna! Dziękujemy,

Chris.

+0

Jak duży jest oryginalny obraz JPG? Istnieje kilka raportów na temat tego rodzaju błędu w przypadku dwóch 6 plików Mpx: http://groups.google.com/group/android-developers/browse_thread/thread/0a6279680d1bd15e – schnaader

Odpowiedz

1

Myślę, że jest - jak to się mówi. Twój obraz jest zbyt duży i ponieważ jest załadowany do strumienia po wyczerpaniu pamięci, wyjątek jest zgłaszany. Nie chodzi nawet o ogólną ilość pamięci, ale o ilość dostępnej aktywności.

+0

Obraz pochodzi z aparatu telefonicznego G1. Rozmiar obrazu to 2048x1536 apx 1,01MB – Chrispix

+0

To wszystko powinno być w porządku, ale potem znowu - nie liczy się skumulowana pamięć, ale ilość została przydzielona przez system do konkretnego zadania. Czy możesz zweryfikować, że twój kod działa z powiedzeniem 500K lub 50K? – Bostone

4

Zmieniłem rozmiar mapy bitowej za pomocą następującego kodu, który prawdopodobnie rozwiązał problem.

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

Upewnij się, że chronisz tworzenie bitmap przed błędami pamięci! W przypadku większości platform Android nie ma zbyt dużo pamięci do działania i szybko się kończy z bitmapami. Pamiętaj też, aby ręcznie odtworzyć mapy bitowe w maksymalnym możliwym stopniu. Zauważyłem, że odśmiecanie może być dość powolne.

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

Najlepszy sposób na GC? myFragileBitmap = null? – Chrispix

+0

Nie zawsze wydaje się, że to robię, z jakiegoś powodu normalnie ustawiam go na wartość null po utylizacji, jednak ... Zakładam, że istnieje pewna magia skia do usuwania bitmap ... – Ralphleon

13

inSampleSize to dobra wskazówka. Ale ustalona wartość często nie działa dobrze, ponieważ duże bitmapy z plików są zwykle plikami użytkownika, które mogą się różnić od małych miniatur do 12-megapikselowych obrazów z kamery cyfrowej.

Oto szybka i brudna procedura ładowania. Wiem, że jest miejsce na ulepszenia, takie jak ładniejsza zakodowana pętla, wykorzystująca moce 2 do szybszego dekodowania i tak dalej. Ale to dopiero początek pracy ...

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, w nowszych API istnieje również wiele BitmapFactory.Option za dopasowanie obrazu do ekranu DPI, ale nie jestem pewien, czy rzeczywiście uprościć wszystko. Używanie android.util.DisplayMetrics.density lub po prostu stały rozmiar przy mniejszym zużyciu pamięci wydaje się działać lepiej imho.

0

Czy sprawdziłeś DDMS? Z tym, z czym się zetknąłem, prawdopodobnie nie jest to rozmiar obrazów, ponieważ Android radzi sobie z dużymi obrazami całkiem dobrze. Jeśli prześledzisz stertę za pomocą DDMS, może się okazać, że masz dużo wolnej pamięci. można „rozwinąć” swoje sterty dodając ten

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

do kodu, aby wymusić sterty się rozwijać. To może sprawić, że będzie to nieco rzadsze. Niestety, z wyjątkiem twierdzi, że nie może przydzielić pewnej ilości bajtów. Powiedz 1M. Jeśli spojrzysz na "darmową" linię, zobaczysz, że największy blok to >> 1M. Jest coś dziwnego, czego nie mogę zrozumieć. Nie ma związku z szybkością przesuwania obrazów. Widziałem w pewnym wątku, który można nazwać "recyklingiem" lub tak w przypadku bitmap. Nadal nie rozumiem, dlaczego miałoby to pomóc, jeśli rozmiar sterty jest o wiele wyższy od podjętego rozmiaru.

1

korzystać z tych opcji w decodefile. nadzieję, że u może elemenate bitmapy przekracza problemu budżetowego 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

Ta metoda pomogła, dzięki kolego! :RE – Xarialon

0

mam ten błąd, gdy zacząłem zmienić rozmiar obrazu z 320x240 do czegoś jak 64x240 (w dół skali), a następnie zaimportować do mojego projektu (ponieważ chciałem poprawić prędkość renderowania i zawierała wiele bezużytecznych regionów alfa do tego momentu).

teraz ostatnia odpowiedź sprawia, że ​​wiele sensu:

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.

myślę, że to, co się ze mną stało. Android automatycznie dekoduje rysunki w bitmapy, (a następnie zapisuje je na stertę, wszystko w czasie kompilacji?)

Zacząłem widzieć błąd, gdy użyłem mniejszej wersji mojego obrazu w czasie wykonywania (skalowałem je w środowisku wykonawczym ponieważ programuję grę VGA z grafiką w stylu retro, używając BitmapFactory.decodeResource i Bitmap.createScaledBitmap).

To musi być jak Marve powiedział: The Heap nie jest wystarczająco duży w moim przypadku po zmniejszeniu mojego rysunku/rysowania i zaimportowaniu go do mojego projektu.

Byłem w stanie pozbyć się mojego wyjątku OutOfMemoryException podczas zmiany rozmiaru obrazu z powrotem na większy rozmiar (320x240), który weryfikuje problem chyba?

5

W nawiązaniu do tego link, należy zwrócić uwagę na błąd outOfMemory można rozwiązać w następujący sposób:

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; 
} 
Powiązane problemy