Search code examples
androidandroid-bitmapandroid-memory

OutOfMemoryError that I don't know when or why happened


So I just noticed this crash on Crashlytics. Apparently it happened 4 times to 3 different users. One of them has a fairly good device (Nexus 5).

Stacktrace:

Fatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 4194316 byte allocation with 3271760 free bytes and 3MB until OOM
   at dalvik.system.VMRuntime.newNonMovableArray(VMRuntime.java)
   at android.graphics.Bitmap.nativeCreate(Bitmap.java)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:831)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:808)
   at android.graphics.Bitmap.createBitmap(Bitmap.java:775)
   at maps.aa.g.a(Unknown Source)
   at maps.aa.i.a(Unknown Source)
   at maps.aa.i.a(Unknown Source)
   at maps.aa.i.b(Unknown Source)
   at maps.ac.o.a(Unknown Source)
   at maps.ac.t.a(Unknown Source)
   at maps.X.K.a(Unknown Source)
   at maps.X.H.a(Unknown Source)
   at maps.X.H.b(Unknown Source)
   at maps.X.y$f.f(Unknown Source)
   at maps.X.y$f.run(Unknown Source)

From this stacktrace, I just can't figure out when or why this crash happens.

I work with Bitmaps on two different places in my app. These are my methods.

Load a drawable and then draw some text on it:

public Bitmap getMarkerBitmap(Context context) {
    Resources resources = context.getResources();
    float scale = resources.getDisplayMetrics().density;
    Bitmap bitmap = null;
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    String text = Integer.toString(reservableCars);
    paint.setColor(Color.WHITE);

    if (reservableCars == 0) {
        bitmap = BitmapFactory.decodeResource(resources, R.drawable.marker_nocars);
    } else if (isPublic()) {
        bitmap = BitmapFactory.decodeResource(resources, R.drawable.marker_public_location_cars);
    } else {
        bitmap = BitmapFactory.decodeResource(resources, R.drawable.marker_corpo_location_cars);
    }

    android.graphics.Bitmap.Config bitmapConfig =
            bitmap.getConfig();
    // set default bitmap config if none
    if(bitmapConfig == null) {
        bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
    }
    // resource bitmaps are imutable,
    // so we need to convert it to mutable one
    bitmap = bitmap.copy(bitmapConfig, true);

    Canvas canvas = new Canvas(bitmap);
    // text size in pixels
    paint.setTextSize((int) (10 * scale));
    // text shadow
    paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);

    // draw text to the Canvas center
    Rect bounds = new Rect();
    paint.getTextBounds(text, 0, text.length(), bounds);
    int x = (bitmap.getWidth() - bounds.width())/2;
    int y = (bitmap.getHeight() + bounds.height())/2;

    canvas.drawText(text, x, y, paint);

    return bitmap;
}

Draw a circle and two letters in it.

public Bitmap drawProfileBitmap(Context context) {
    Paint paint = new Paint();
    Paint circlePaint = new Paint();
    Rect bounds = new Rect();
    String text = Character.toString(firstName.charAt(0)) + Character.toString(lastName.charAt(0));
    int pixelvalue = (int) (70 * context.getResources().getDisplayMetrics().density * 0.5f);
    Bitmap bitmap = Bitmap.createBitmap(pixelvalue, pixelvalue, Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);

    paint.setColor(Color.WHITE);
    paint.setTextSize(40f);
    paint.setAntiAlias(true);
    paint.setTextAlign(Paint.Align.CENTER);
    paint.getTextBounds(text, 0, text.length(), bounds);

    circlePaint.setColor(context.getResources().getColor(R.color.primary));
    circlePaint.setAntiAlias(true);

    canvas.drawCircle(bitmap.getWidth()/2, bitmap.getHeight()/2, bitmap.getHeight(), circlePaint);
    canvas.drawText(text, bitmap.getWidth()/2, (bitmap.getHeight() + bounds.height())/2, paint);
    return bitmap;
}

Could this crash happen because of one of the above methods? The first one is called many times. For each marker drawn on Google Map - but there are never more than 15-20 markers on the map.

The second one is called only once each time the app starts.


Solution

  • try to recucle bitmap when it not used

    if ( mBitmap != null ) mBitmap.recycle();  
         mBitmap  = null; 
    

    also (if it possible), you need to remove all links to you bitmap. for ex in case of using Image view: mImageView.setImageBitmap(null); and ect.