web-dev-qa-db-fra.com

Android OutOfMemoryError :?

Je reçois sporadiquement une OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB) dans l'une de mes applications. Que puis-je faire pour diagnostiquer cela?

  01-09 10:32:02.079: E/dalvikvm(8077): Out of memory: Heap Size=49187KB, Allocated=41957KB, Limit=49152KB
  01-09 10:32:02.079: E/dalvikvm(8077): Extra info: Footprint=48611KB, Allowed Footprint=49187KB, Trimmed=7852KB
  01-09 10:32:02.079: D/skia(8077): --- decoder->decode returned false
  01-09 10:32:02.079: D/AndroidRuntime(8077): Shutting down VM
  01-09 10:32:02.079: W/dalvikvm(8077): threadid=1: thread exiting with uncaught exception (group=0x40a97228)
  01-09 10:32:02.079: E/AndroidRuntime(8077): FATAL EXCEPTION: main
  01-09 10:32:02.079: E/AndroidRuntime(8077): Java.lang.OutOfMemoryError: (Heap Size=49187KB, Allocated=41957KB)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.Java:486)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.graphics.drawable.Drawable.createFromResourceStream(Drawable.Java:773)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.content.res.Resources.loadDrawable(Resources.Java:2044)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.content.res.Resources.getDrawable(Resources.Java:675)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.view.View.setBackgroundResource(View.Java:11776)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.blsk.bigtoss.ImageLoader.DisplayImage(ImageLoader.Java:81)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.blsk.bigtoss.MatchActivity$MatchAsyncTask.onPostExecute(MatchActivity.Java:1768)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.AsyncTask.finish(AsyncTask.Java:602)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.AsyncTask.access$600(AsyncTask.Java:156)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.Java:615)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.Handler.dispatchMessage(Handler.Java:99)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.os.Looper.loop(Looper.Java:156)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Android.app.ActivityThread.main(ActivityThread.Java:4987)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Java.lang.reflect.Method.invokeNative(Native Method)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at Java.lang.reflect.Method.invoke(Method.Java:511)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:784)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:551)
  01-09 10:32:02.079: E/AndroidRuntime(8077):   at dalvik.system.NativeStart.main(Native Method)
  01-09 10:32:02.099: E/EmbeddedLogger(1612): App crashed! Process: com.blsk.bigtoss
  01-09 10:32:02.099: E/EmbeddedLogger(1612): App crashed! Package: com.blsk.bigtoss v6 (1.2)
  01-09 10:32:02.129: E/EmbeddedLogger(1612): Application Label: Cricket

C'est la ligne où cela se produit:

LinearLayout resultMatchHeaderContainer = new LinearLayout(activity); 

if (!resultImagePath.equals("")) {   
    imageLoader.DisplayImage(resultImagePath,resultMatchHeaderContainer, -1,modifiedHeight, R.drawable.matches_placeholder_result2x);
} else {
    try {
        resultMatchHeaderContainer.setBackgroundResource(R.drawable.matches_placeholder_result2x); 
    } catch (OutOfMemoryError e) {         
        e.printStackTrace();
    }
}
30
NagarjunaReddy

peut-être que cela vous aide?

ajouter un manifeste

Android> v3

<application
    ....
       Android:largeHeap="true"> 
42
SKULL

Correctifs courants:

1. Fixez vos contextes:

Essayez d'utiliser le contexte approprié: par exemple, comme un Toast peut être vu dans de nombreuses activités au lieu d'une seule, utilisez getApplicationContext() pour les toasts, et puisque les services peuvent continuer à fonctionner même si une activité est terminée, démarrez un service avec :

Intent myService = new Intent(getApplicationContext(), MyService.class)

Utilisez ce tableau comme guide rapide pour déterminer le contexte approprié: enter image description here

Original article sur le contexte ici .

2. Vérifiez que vous terminez réellement vos services.

Par exemple, j'ai un intentionService qui utilise l'API du service de localisation Google. Et j'ai oublié d'appeler googleApiClient.disconnect();:

//Disconnect from API onDestroy()
    if (googleApiClient.isConnected()) {
        LocationServices.FusedLocationApi.removeLocationUpdates(googleApiClient, GoogleLocationService.this);
        googleApiClient.disconnect();
    }

3. Vérifiez l'utilisation des images et des bitmaps:

Si vous utilisez la bibliothèque Picasso de Square , j'ai constaté que je perdais de la mémoire en n'utilisant pas la .fit(), ce qui a considérablement réduit l'empreinte mémoire de 50 Mo en moyenne à moins de 19 Mo:

Picasso.with(ActivityExample.this)                   //Activity context
                .load(object.getImageUrl())           
                .fit()                                //This avoided the OutOfMemoryError
                .centerCrop()                         //makes image to not stretch
                .into(imageView);

4. Si vous utilisez des récepteurs de diffusion, annulez leur enregistrement.

5. Si vous utilisez Java.util.Observer (Modèle d'observateur):

Assurez-vous d'utiliser deleteObserver(observer);

34
CommonSenseCode

Vous pouvez faire ce qui suit pour éviter cela.

Drawable drawable = resultMatchHeaderContainer.getDrawable();

if (drawable instanceof BitmapDrawable) {
    BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
    if (bitmapDrawable != null) {
        Bitmap bitmap = bitmapDrawable.getBitmap();

        if (bitmap != null && !bitmap.isRecycled())
           bitmap.recycle();
    }
}

Le chargement de Bitmap dans Imageview a toujours été une cause de problème de manque de mémoire, il est très courant, nous devons donc manipuler très attentivement imageview et bitmaps. Ce que vous pouvez faire, c'est tout en définissant une image bitmap d'arrière-plan sur votre image, commencez par obtenir le dessin et recyclez-le afin qu'il soit supprimé de la mémoire, puis définissez la nouvelle image bitmap. Cela vous aidera à éviter tout problème de MOO. Plus loin. Vous pouvez utiliser BitmapFactoryOptions pour réduire la taille de votre bitmap. comme:

// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        FileInputStream stream1 = new FileInputStream(f);
        BitmapFactory.decodeStream(stream1, null, o);
        stream1.close();

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_WIDTH
                    || height_tmp / 2 < REQUIRED_HIGHT)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        FileInputStream stream2 = new FileInputStream(f);
        Bitmap bitmap = BitmapFactory.decodeStream(stream2, null, o2);
        stream2.close();
        return bitmap;
    } catch (FileNotFoundException e) {
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
8
Avtar Guleria

Avant de charger des images en mémoire, compressez vos images à l'aide

Bitmap original = BitmapFactory.decodeStream(getAssets().open("1024x768.jpg"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
original.compress(Bitmap.CompressFormat.PNG, 100, out);
Bitmap decoded = BitmapFactory.decodeStream(new ByteArrayInputStream(out.toByteArray()));

Log.e("Original   dimensions", original.getWidth()+" "+original.getHeight());
Log.e("Compressed dimensions", decoded.getWidth()+" "+decoded.getHeight());  

Si vous obtenez votre bitmap à partir d'une ressource, auquel cas la dimension bitmap dépendra de la densité de l'écran du téléphone

Bitmap bitmap=((BitmapDrawable)getResources().getDrawable(R.drawable.img_1024x768)).getBitmap();
Log.e("Dimensions", bitmap.getWidth()+" "+bitmap.getHeight());
1
rajahsekar

Cela peut se produire pour plusieurs raisons, vous conservez peut-être trop longtemps les références à d'autres parties de votre code. Vous pouvez être en train de charger sur de grandes images bitmap qui, avec s'accrochent à de nombreuses références vous donne un MOO, etc.

Normalement, lorsqu'un MOO se produit, un hprof (instantané du tas) est créé à la racine de la carte SD (ou du stockage interne si la carte SD n'existe pas), qui peut être lu par des outils comme Eclipse MAT (inclus dans les outils Android si vous utilisez Eclipse). Premier pourrait avoir besoin de convertir le hprof avec hprof-conv outil. Voici un didacticiel sur la façon d'utiliser Eclipse MAT: Investigating Your RAM Usage . Le rapport sur les suspects de fuite est une bonne première lecture lorsque hprof est chargé dans Eclipse MAT

Après le profilage, vous pouvez lire comment charger efficacement des images à partir de Affichage efficace des bitmaps

Il existe également plusieurs bibliothèques de chargement d'images populaires telles que chargeur d'image universel et picasso disponibles, qui font facilement ce dont vous avez besoin.

1
Magnus

sourire Bitmap final = BitmapFactory.decodeResource (getResources (), R.drawable.Emo_im_happy);

Appel

String pathname=BitMapToString(smile);

puis appeler

setImagesNew(linearview,pathname,activity);

...

public String BitMapToString(Bitmap bitmap) { 
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
             bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); 
        byte[] b = baos.toByteArray();
      String temp = Base64.encodeToString(b, Base64.DEFAULT);
      return temp;
 }


 public static void setImagesNew(LinearLayout linearLayout, String pathName,
                Activity activity) {

            Bitmap bmp = decodeSampledBitmapFromResource(pathName,
                    getDeviceWidth(activity), getDeviceHeight(activity));

linearLayout.setBackgroundDrawable(bmp);


            bmp = null;
            System.gc();
            Runtime.getRuntime().gc();

        }
    public static Bitmap decodeSampledBitmapFromResource(String pathName,
            int reqWidth, int reqHeight) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(pathName, options);
    }

    public static int calculateInSampleSize(BitmapFactory.Options options,
            int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and
            // keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    @SuppressLint("NewApi")
    public static int getDeviceWidth(Activity activity) {
        int deviceWidth = 0;

        Point size = new Point();
        WindowManager windowManager = activity.getWindowManager();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            windowManager.getDefaultDisplay().getSize(size);
            deviceWidth = size.x;
        } else {
            Display display = windowManager.getDefaultDisplay();
            deviceWidth = display.getWidth();
        }
        return deviceWidth;
    }

    @SuppressLint("NewApi")
    public static int getDeviceHeight(Activity activity) {
        int deviceHeight = 0;

        Point size = new Point();
        WindowManager windowManager = activity.getWindowManager();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            windowManager.getDefaultDisplay().getSize(size);
            deviceHeight = size.y;
        } else {
            Display display = windowManager.getDefaultDisplay();
            deviceHeight = display.getHeight();
        }
        return deviceHeight;
    }

veuillez mettre toutes les fonctions dans votre activité et appeler uniquement setImageNew() et passer le paramètre dans imageview, sdcardpathname et activity

J'espère qu'il ne plantera pas après avoir implémenté ce code. parce que je me pose le même problème que toi ..

1
dipali

Cela peut se produire si la ressource bitmap n'est pas supprimée correctement. Il est préférable de lire les dimensions pour voir si cela correspond à la mémoire. http://developer.Android.com/training/displaying-bitmaps/load-bitmap.html

0
Selvan