title: Suggestions to avoid bitmap Out of Memory error
body: <p>I am working on an android application. The application has a view containing lots of image. I had an error, I will try to give as much information as possible hoping someone can give me some suggestions.</p>
  
  <p>The application was working great on all the local testings. However, I received lots of crashes from users: <code>java.lang.OutOfMemoryError: bitmap size exceeds VM budget</code></p>
  
  <p>This is the stack trace</p>
  
  <pre><code>0       java.lang.OutOfMemoryError: bitmap size exceeds VM budget
  1   at  android.graphics.Bitmap.nativeCreate(Native Method)
  2   at  android.graphics.Bitmap.createBitmap(Bitmap.java:507)
  3   at  android.graphics.Bitmap.createBitmap(Bitmap.java:474)
  4   at  android.graphics.Bitmap.createScaledBitmap(Bitmap.java:379)
  5   at  android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:498)
  6   at  android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:473)
  7   at  android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
  8   at  android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:359)
  9   at  android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:385)
  </code></pre>
  
  <p>My biggest problem is that I was not able to reproduce the issue locally even on old devices.</p>
  
  <p>I have implemented lots of things to try to resolve this:</p>
  
  <ol>
  <li><strong>No memory leaks</strong>: I made sure there is no memory leaks at all. I removed the views when I dont need them. I also recycled all the bitmaps and made sure the garbage collector is working as it should. And I implemented all the necessary steps in the <code>onDestroy()</code> method</li>
  <li><strong>Image size scaled correctly</strong>: Before getting the image I get its dimension and calculate the <code>inSampleSize</code>.</li>
  <li><strong>Heap size</strong>: I also detect the Max Heap size before getting the image and make sure there is enough space. If there is not enough I rescale the image accordingly.</li>
  </ol>
  
  <p><strong>Code to calculate the correct inSampleSize</strong></p>
  
  <pre><code>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 &gt; reqHeight || width &gt; reqWidth)
        {
           if(width &gt; height)
           {
              inSampleSize = Math.round((float) height / (float) reqHeight);
           }
           else
           {
              inSampleSize = Math.round((float) width / (float) reqWidth);
           }
        }
        return inSampleSize;
     }
  </code></pre>
  
  <p><strong>Code to get the bitmap</strong></p>
  
  <pre><code>    // decodes image and scales it to reduce memory consumption
     private static Bitmap decodeFile(File file, int newWidth, int newHeight)
     {// target size
        try
        {
  
           Bitmap bmp = MediaStore.Images.Media.getBitmap(getContext().getContentResolver(), Uri.fromFile(file));
           if(bmp == null)
           {
              // avoid concurrence
              // Decode image size
              BitmapFactory.Options option = new BitmapFactory.Options();
  
              // option = getBitmapOutput(file);
  
              option.inDensity = res.getDisplayMetrics().densityDpi &lt; DisplayMetrics.DENSITY_HIGH ? 120 : 240;
              option.inTargetDensity = res.getDisplayMetrics().densityDpi;
  
              if(newHeight &gt; 0 &amp;&amp; newWidth &gt; 0) 
                  option.inSampleSize = calculateInSampleSize(option, newWidth, newWidth);
  
              option.inJustDecodeBounds = false;
              byte[] decodeBuffer = new byte[12 * 1024];
              option.inTempStorage = decodeBuffer;
              option.inPurgeable = true;
              option.inInputShareable = true;
              option.inScaled = true;
  
              bmp = BitmapFactory.decodeStream(new FileInputStream(file), null, option);
              if(bmp == null)
              {
                 return null;
              }
  
           }
           else
           {
              int inDensity = res.getDisplayMetrics().densityDpi &lt; DisplayMetrics.DENSITY_HIGH ? 120 : 240;
              int inTargetDensity = res.getDisplayMetrics().densityDpi;
              if(inDensity != inTargetDensity)
              {
                 int newBmpWidth = (bmp.getWidth() * inTargetDensity) / inDensity;
                 int newBmpHeight = (bmp.getHeight() * inTargetDensity) / inDensity;
                 bmp = Bitmap.createScaledBitmap(bmp, newBmpWidth, newBmpHeight, true);
              }
           }
  
           return bmp;
        }
        catch(Exception e)
        {
           Log.e("Error calling Application.decodeFile Method params: " + Arrays.toString(new Object[]{file }), e);
        }
        return null;
     }
  </code></pre>
  
  <p><strong>Code to calculate image size based on Heap size for older devices</strong></p>
  
  <pre><code>private void calculateImagesSize()
     {
        // only for android older than HoneyComb that does not support large heap
        if(Build.VERSION.SDK_INT &lt; Constants.HONEYCOMB)
        {
           long maxHeapSize = Runtime.getRuntime().maxMemory();
           long maxImageHeap = maxHeapSize - 10485760;
           if(Application.getResource().getDisplayMetrics().densityDpi &gt;= DisplayMetrics.DENSITY_XHIGH)
           {
              maxImageHeap -= 12 * 1048576;
           }
           if(maxImageHeap &lt; (30 * 1048576))
           {
              int screenHeight = Math.min(Application.getResource().getDisplayMetrics().heightPixels, Application.getResource()
                 .getDisplayMetrics().widthPixels);
              long maxImageSize = maxImageHeap / 100;
              long maxPixels = maxImageSize / 4;
              long maxHeight = (long) Math.sqrt(maxPixels / 1.5);
              if(maxHeight &lt; screenHeight)
              {
                 drawableHeight = (int) maxHeight;
                 drawableWidth = (int) (drawableHeight * 1.5);
              }
           }
        }
     }
  </code></pre>
  
  <p>I think the problem is with the Heap, maybe sometimes the os doesn't allow the application to use the maxheapsize. Also my biggest problem is that I was not able to reproduce the issue, so when I try a fix I have to wait a little to see if users are still getting the error.</p>
  
  <p>What more could I try to avoid Out of memory issues? Any suggestions would be greatly appreciated. Thanks a lot</p>