Avoiding Running Out Of Memory
 
I???ve implemented a simple picture picker widget in this Android app I???m
working on. Here???s the guts of the code that initializes it:
        ThePics.Clear();
        final String ExternalStorage =
            android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
        final String[] Places =
          {
            ExternalStorage.concat("/Pictures"),
            ExternalStorage.concat("/DCIM"),
          };
        for (String Place : Places)
          {
            final java.io.File ThisDir = new java.io.File(Place);
            if (ThisDir.isDirectory())
              {
                for (java.io.File Item : ThisDir.listFiles())
                  {
                    android.graphics.Bitmap ThisImage =
                        android.graphics.BitmapFactory.decodeFile(Item.getAbsolutePath());
                    if (ThisImage != null)
                      {
                        ThePics.AppendItem(ThisImage, Item, Item.getName());
                      } /*if*/
                  } /*for*/
              } /*if*/
          } /*for*/
        ThePics.notifyDataSetChanged();
The first time after the app was launched, bringing up the picker would
work. But on the second time, the app would crash with
???java.lang.OutOfMemoryError: bitmap size exceeds VM budget??? in
android.graphics.BitmapFactory.decodeFile.
Even rotating the phone (which causes the re-creation of the activity)
triggered the crash.
Just to make it clear, the widget does NOT keep a reference to the Bitmap
that is passed; it creates a copy, scaled as necessary so as not to exceed a
maximum thumbnail size (160x160 pixels). So each thumbnail should take no
more than about 100K max, and my phone only has about a dozen pictures on
it.
I went over the ???Avoiding Memory Leaks??? article
<http://developer.android.com/resources/articles/avoiding-memory-leaks.html>,
looking carefully for unwanted references that might be preventing bitmaps
from being freed.
Finally, one simple change did the trick: after that ThePics.Append call
above, I added
                        ThisImage.recycle();
and that fixed it! Now I can bring up the picker multiple times during a
single app invocation, rotate the phone any number of times I like, and it
all works nicely.
So the question is: why was the garbage collector being so tardy in
reclaiming all those loaded full-size images?