9

I have a list that shows thumbnails (small images) downloaded on the fly from the web. At some point, the process runs out of memory. How can I tell that the free memory is about to run off, so I can stop downloading more images?

I would like to know it in advance in order not to be on the edge of out of memory.

Note: It is not a memory leak, just lots of downloaded bitmaps.

Thanks.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
  • I'll elaborate a bit more. In order not to download every image several times, I cache the downloaded images in the activity and replace the old images - LRU. I would like to know when to stop caching or to bound the size of the LRU. – AlikElzin-kilaka Apr 07 '11 at 11:15
  • I've got the same problem, I tried softreferences and whatever... –  Apr 07 '11 at 16:32

4 Answers4

27

1) You have to be your own browser.

Download your thumbs to the SDCard rather than keeping them in RAM. Shrink/rotate them before you save them so that when you next need to load them the load is "free" from the SDCard instead of expensive from the internets. (Ie: like any browser, use a local file cache).

Release any interim Bitmap objects you may create to do this.

Learn how to use the "inSampleSize" param to unpack Bitmaps at less than original resolution.

If the files you write end in an image extension (.jpg, etc) they will appear in the Gallery, so don't save your thumbs with obvious image filenames.

2) Create a tiered cache system (Bitmap > SDCard > Internets).

When you unpack a thumbnail, save it in a SoftReference cache. If you need to use that thumbnail, ask for it from the cache. If the VM needed more memory, your SoftReference instance may return null.

If you get null from your bitmap cache, then check to see if you've already put your url on the SD card and load it into the bitmap cache from there.

If you get null from your filesystem, then go download the image from the internet and save it to SDCard and stick it in your bitmap cache.

3) Release resources that aren't being used.

In the same way, make sure you clear the Bitmaps from the Views they have been placed in as soon as the View is offscreen (if your Views live in a ListView or other Adapter-based element, this is essentially "free" from recycling the View elements) -- However, if you have ImageViews instantiated with Bitmaps and they're not immediately displayed on the screen, you're probably wasting heap.

You can simply call setImageBitmap(null); on an ImageView and the reference to the Bitmap will be dropped (so that if the only ref is the SoftReference when it's not being used).

4) Pay attention to what thread you are in.

Remember, you must download bitmaps from a non-UI thread (we use a Service instance to act as a queue of intent requests), and you must attach bitmaps to View instance only in the UI thread.

You'll need to create a good queued system to load everything into your bitmap cache off the UI thread and then use a Handler to tell your bitmap cache to fill ImageViews on the UI thread.

5) Pay attention to your download Queues.

If you're like us and you have both thumbs and full-sized images, you need to either manually use a priority queue to put your image requests before you thumb requests, or use two different Services (that enqueue their separate Intents) to download thumbs vs full images.

Otherwise you might queue up a screen full of thumb downloads but not respond with a full image until after all of the thumbs complete.

6) Ask the system how much RAM you have.

  Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
  Debug.getMemoryInfo(memoryInfo);

7) "onLowMemory()" doesn't do what you expect.

It is for when the user is running too many applications on the phone and the OS needs to recover physical memory from all of the running apps.

This is totally separate from running out of application VM heap like you'll easily do by loading too many bitmaps.

To the best of my knowledge you will not get a warning, you'll just crash (tho you can track memory info with the above call).

Hope that helps with trying to make something smart about downloading and displaying thumbs from the internets.

mig

mig
  • 1,497
  • 1
  • 11
  • 6
  • Re using "SoftReference". Now, an LruCache is recommended instead. http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html --- "In the past, a popular memory cache implementation was a SoftReference or WeakReference bitmap cache, however this is not recommended. Starting from Android 2.3 (API Level 9) the garbage collector is more aggressive with collecting soft/weak references which makes them fairly ineffective." – ToolmakerSteve Jul 21 '14 at 23:06
3

I use SoftReference to hold the bitmap objects. The list only needs the current visible images. Thus, I never need to worry about running out of space.

The minus is that when I see the images, scroll down (causing some SoftReferences to clear the Bitmaps), then scroll back again to the same place - the images get downloaded again :(

Also, the SoftReferences get cleared very fast. I would expect them to save the inner bitmap longer.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
  • Very similar to the answer: http://stackoverflow.com/questions/1945201/android-image-cache/1945518#1945518 – AlikElzin-kilaka Apr 07 '11 at 16:56
  • Nowadays, use LruCache rather than SoftReferences. To avoid the problem you are having with the references getting cleared more aggressively than you expect. http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html – ToolmakerSteve Jul 21 '14 at 23:18
2

You should use inSampleSize option of BitmapFactory.Options while creating the bitmaps.

Also, some of the tips in Android: out of memory exception in Gallery has been useful for me in keeping a check on the memory available.

Community
  • 1
  • 1
Rajath
  • 11,787
  • 7
  • 48
  • 62
  • Regardless the size, if I have too much images, eventually, the process runs out of memory. – AlikElzin-kilaka Apr 07 '11 at 11:16
  • Of course. And ultimately, you have to stop at a finite number of images. The question should really be how to push this limit as much as acceptably possible. – Rajath Apr 07 '11 at 11:24
-1

You can over-ride the Activity's onLowMemory() method for custom handling such scenarios

Swaroop
  • 908
  • 1
  • 12
  • 25