title: Android: out of memory exception in Gallery
body: <p>My app shows a list of 9 categories and each category displays a Gallery-based coverflow (graciously offered by Neil Davies <a href="http://www.inter-fuser.com/2010/02/android-coverflow-widget-v2.html" rel="nofollow noreferrer">here</a>) with images of the selected category.  </p>
  
  <p>The images are fetched from the Web, each ranging from 300K to 500K in size, and stored in an arrayList of Drawables. This data is bound to the coverflow using a BaseAdapter (code below).<br>
  Every time I exit the coverflow and go back to the list of categories, I clear the arrayList (again, code below).  </p>
  
  <p>In scenario 1, my arrayList contains 5 Drawables. In this scenario, I can freely browse all the categories and show their images. During my test I cycled through all the categories for 5 times, which seems enough to determine that there is no problem.  </p>
  
  <p>In scenario 2, my arrayList contains 10 drawables. In this scenario, I get an OutOfMemoryError exception while going through images inside the 5th or 6th categeory:  </p>
  
  <pre>
  07-13 08:38:21.266: ERROR/dalvikvm-heap(2133): 819840-byte external allocation too large for this process.
  07-13 08:38:21.266: ERROR/(2133): VM won't let us allocate 819840 bytes
  07-13 08:38:21.277: DEBUG/skia(2133): --- decoder->decode returned false
  07-13 08:38:21.287: WARN/dalvikvm(2133): threadid=25: thread exiting with uncaught exception (group=0x4001b188)
  07-13 08:38:21.296: ERROR/AndroidRuntime(2133): Uncaught handler: thread Thread-64 exiting due to uncaught exception
  07-13 08:38:21.308: ERROR/AndroidRuntime(2133): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
  07-13 08:38:21.308: ERROR/AndroidRuntime(2133):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
  07-13 08:38:21.308: ERROR/AndroidRuntime(2133):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459)
  07-13 08:38:21.308: ERROR/AndroidRuntime(2133):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323)
  07-13 08:38:21.308: ERROR/AndroidRuntime(2133):     at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
  07-13 08:38:21.308: ERROR/AndroidRuntime(2133):     at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
  </pre>  
  
  <p>This doesn't make sense to me. If I am leaking memory I would have expected to crash at some point in scenario 1, but I went through all the categories a substantial number of times and didn't crash. I also used the Memory Analyzer plugin for Eclipse which didn't present any potential culprits.</p>
  
  <p>If the system couldn't handle 10 images, like in scenarion 2, I would have expected to crash in the first category, but I crash only after 5 or 6 categories.  </p>
  
  <p>The coverflow's adapter functions:    </p>
  
  <pre><code>public int getCount() {
       return DataManager.getInstance().getImageBufferInstance().getImageArraySize(); 
  }
  
  public Object getItem(int position) {    
       return DataManager.getInstance().getImagesBuffer().get(position);
  }
  
  public long getItemId(int position) {
       return position;
  }
  
  public View getView(int position, View convertView, ViewGroup parent) {      
           ImageView i;
           if (convertView == null)
               i = new ImageView(mContext);
           else
               i = (ImageView)convertView;
           Drawable bufferedImage = (Drawable)getItem(position);
           Log.v("getView", "position: " + position);
           i.setImageDrawable(bufferedImage);
  
           i.setLayoutParams(new CoverFlow.LayoutParams(Utils.getInstance().getScreenWidth() / 2,
                   Utils.getInstance().getScreenHeight() / 2));
           i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 
  
           try{
           //Make sure we set anti-aliasing otherwise we get jaggies
           BitmapDrawable drawable = (BitmapDrawable) i.getDrawable();
           drawable.setAntiAlias(true);
           }
           catch (Exception e)
           {
               Log.v("getView", "Exception: " + e.toString());
           }
           return i;      
       }
  </code></pre>
  
  <p>populating the data source upon entry to the category:  </p>
  
  <pre><code>for (int i = 0; i &lt; ImageBuffer.getInstance().getImageArraySize(); i++)  
  {  
    String imageUrl = ImageBuffer.getInstance().getImageUrl(i);  
    Log.v("Initial", imageUrl);  
    Drawable fullImage = AsyncImageLoader.getInstance().loadImageByUrl(imageUrl);  
    ImageBuffer.getInstance().getImages().add(i, fullImage);  
  
  }
  </code></pre>
  
  <p>clearing the data source when exiting the category (in finish()):  </p>
  
  <pre><code>for (int i = 0; i &lt; ImageBuffer.getInstance().getImageArraySize(); i++)  
  {  
    if (ImageBuffer.getInstance().images.get(i) != null)  
              {  
                  ImageBuffer.getInstance().images.get(i).setCallback(null);  
                  ImageBuffer.getInstance().images.set(i, null);  
              }    
  
  }
  </code></pre>
  
  <p>EDIT:</p>
  
  <p>OK, I applied Mathias' LogHeap function on my coverflow and here are some outputs.
  Prior to loading the first gallery:</p>
  
  <pre>
  DEBUG/Application(5221): debug. =================================
  DEBUG/Application(5221): debug.heap native: allocated 6.20MB of 6.28MB (0.07MB free) in [com.example.Coverflow]
  DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (0.00MB free)
  DEBUG/dalvikvm(5221): GC freed 4558 objects / 638152 bytes in 84ms
  DEBUG/dalvikvm(5221): GC freed 17 objects / 808 bytes in 67ms
  </pre>  
  
  <p>After entering the first gallery:  </p>
  
  <pre>
  DEBUG/Application(5221): debug. =================================
  DEBUG/Application(5221): debug.heap native: allocated 14.90MB of 16.89MB (0.07MB free) in [com.example.Coverflow]
  DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free)
  DEBUG/dalvikvm(5221): GC freed 357 objects / 50080 bytes in 68ms
  DEBUG/dalvikvm(5221): GC freed 353 objects / 27312 bytes in 67ms
  </pre>
  
  <p>After existing the first gallery:</p>
  
  <pre>
  DEBUG/Application(5221): debug. =================================
  DEBUG/Application(5221): debug.heap native: allocated 14.83MB of 16.89MB (0.11MB free) in [com.example.Coverflow]
  DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free)
  DEBUG/dalvikvm(5221): GC freed 330 objects / 17920 bytes in 77ms
  DEBUG/dalvikvm(5221): GC freed 13 objects / 760 bytes in 67ms
  </pre>
  
  <p>After entering the fifth gallery:</p>
  
  <pre>
  DEBUG/Application(5221): debug. =================================
  DEBUG/Application(5221): debug.heap native: allocated 16.80MB of 23.32MB (0.08MB free) in [com.example.Coverflow]
  DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free)
  DEBUG/dalvikvm(5221): GC freed 842 objects / 99256 bytes in 73ms
  DEBUG/dalvikvm(5221): GC freed 306 objects / 24896 bytes in 69ms
  </pre>
  
  <p>After exiting the fifth gallery:</p>
  
  <pre>
  DEBUG/Application(5221): debug. =================================
  DEBUG/Application(5221): debug.heap native: allocated 16.74MB of 23.32MB (0.11MB free) in [com.example.Coverlow]
  DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free)
  DEBUG/dalvikvm(5221): GC freed 331 objects / 18184 bytes in 68ms
  DEBUG/dalvikvm(5221): GC freed 60 objects / 3128 bytes in 68ms
  </pre>  
  
  <p>It seems that more and more memory is allocated when entering a gallery, but very little is released after exiting. Am I not clearing my drawables properly? For each element in my arrayList of drawables I call setCallBack(null) and set the element to null. Is that not enough?<br>
  Desperate for any insight.<br>
  Thanks</p>