2

In my application, I would like to load some amount of data into memory when first needed and keep it there in case another part of the application wants to use it. The same data would be accessed from a couple of different Activity'es, but by far not all the user could interact with. So, when not working with the relevant part of my application, I would like Android to feel free to discard the data, reloading them again at need. Note that it is unpredictable for me what the user will do, so I want Android to free the data only if hasn't been used for some time. What is a good approach to doing this?

I thought of creating a class that would be only used statically, loading the data in its static initialisation block. However, I am not sure if Dalvik would ever discard any static data stored this way. I have read something on class loaders but I have no idea what loader is used in loading my class and how it could potentially become discarded. Perhaps someone does...?

Another way I came up with is using weak reference to keep an instance of the data-holding class (non-static, obviously) but here I am afraid that the GC could decide it's useless when no Activity is currently actively operating it, even when memory is no concern at that moment. (In that case, I would like to keep the data loaded.)

The loading of my data is costly. I want, if possible, to destroy it only when the system is running out of memory or when the application exits.

The Vee
  • 11,420
  • 5
  • 27
  • 60
  • See java.util.WeakHashMap, and the underlying WeakReference, SoftReference etc. – user207421 Jan 02 '13 at 01:23
  • Why the downvotes, and why on earth is this not constructive? When there is an answer in the JDK? – user207421 Jan 02 '13 at 01:26
  • 2
    I didn't understand it either. This is, in my opinion, a good question. – tuga Jan 02 '13 at 01:27
  • 1
    Upvoted. Stackoverflow recently started to be "invaded" by high-reputation-score (but actually poorly educated) users who downvote posts (of new users) that they think to be "not constructive" -- which are, actually, constructive. They think they're some sort of real experts. Miserable. So, I suggest that high reputation users shouldn't be taken seriously either exclusively based on reputation. – Thomas Calc Jan 02 '13 at 01:30
  • (It's probably psychology -- they feel some sort of power or importance in that way... I wish all very-high-rep users would be like e.g. Peter Lawrey, i.e. honest and good experts.) – Thomas Calc Jan 02 '13 at 01:32
  • 2
    I've seen quite a bit of it recently too. Questions that you don't personally understand are not *ipso facto* 'not real' or 'not constructive'. If there was a way for moderators to pursue this with those concerned I would be very much in favour. – user207421 Jan 02 '13 at 01:34
  • Just as a side note, in mobile software/Android, it's still good practice to keep things deterministic. (Of course, it depends on the concrete application whether this results in noticeable benefits or not.) BTW as far as I experienced, Android clears SoftReferences quite fast, so I didn't find them too useful. (I remember some materials how to trick this, can't google them now, sorry.) – Thomas Calc Jan 02 '13 at 01:37

3 Answers3

3

You can use SoftReferences. Take a look at:

http://docs.oracle.com/javase/6/docs/api/java/lang/ref/SoftReference.html

With SoftReferences you can achieve what you need: " I want, if possible, to destroy it only when the system is running out of memory or when the application exits."

tuga
  • 331
  • 2
  • 5
  • Thank you! For some reason, I was not aware of `SoftReference`s. It seems that in the low-profile conditions of Android, there are some drawbacks to them (http://developer.android.com/reference/java/lang/ref/SoftReference.html), but it certainly pointed me in the right direction and gave me the important references to read through! – The Vee Jan 02 '13 at 01:35
  • You can also use a cache API like EhCache or JCS. It's up to you now ;) – tuga Jan 02 '13 at 01:40
3

It sounds like SoftReferences are what you need. These are cleared at the garbage collector's discretion when it detects that there is a memory shortfall.

If you read the class javadoc, it gives some hints about how to prevent recently used cache entries from being reclaimed.


For the record, classloaders won't help you manage instances of a class. But making the cache a static should allow the cached objects to be discarded if the cache class gets unloaded.


FOLLOWUP

My data is a solid block that would be represented by a single object.

This rather changes things. If you have a single object to cache, then LRU makes no sense. Basically it sounds like you want to hang onto the object as long as possible ... without trigger OOMEs by hanging onto it too long. This is kind of hard. Indeed, doing a perfect job is going to entail correctly predicting what the user is going to do ... which is clearly impossible.

Possibly the best strategy is to make use of the reference enqueing mechanism, and implement the queue processor to make an "intelligent" choice between letting the object die or recreating the soft link. The "intelligence" might entail looking at how much free memory there is, and / or how long it was since the object was last used. But beware!! If you get this wrong you can cause OOMEs or cause the platform to spend lots of time thrashing the garbage collector.

If I set up the cache to hold 1 object, it would be equivalent to a hard reference, wouldn't it?

Nope. If you use a SoftReference the GC will break the reference if it is running out of memory.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thank you for your follow-up! In my comment about the strong reference equivalence (sorry, not "hard", I stand corrected), I was talking about `LruCache`, not `SoftReference`. It still seems to me that the documentation clearly states that—that it would keep one strong reference. – The Vee Jan 03 '13 at 00:18
2

Take a look at SoftReference gets garbage collected too early

You can also look into LruCache if your looking to cache some data in memory your app. http://developer.android.com/reference/android/support/v4/util/LruCache.html

For a longer lived disk based cache take a look at Android Objects Cache

You can find the DiskLruCache source at https://github.com/JakeWharton/DiskLruCache/

Community
  • 1
  • 1
Akos Cz
  • 12,711
  • 1
  • 37
  • 32
  • Thanks! I'm not sure if `LruCache` would help here. My data is a solid block that would be represented by a single object. If I set up the cache to hold 1 object, it would be equivalent to a hard reference, wouldn't it? – The Vee Jan 02 '13 at 01:51
  • Does all of you data need to be in memory all at one time? If not, then you might want to rethink your caching strategy by breaking up your data into smaller chunks which you can cache more efficiently. – Akos Cz Jan 02 '13 at 01:58
  • According to what I have learned so far, it seems I will indeed have to rethink this. Unfortunately, it will mean substantial changes to the logic of both the use and the loading of my data (think of unpacking some resources compressed using a custom compression method which is extremely space-effective in this case but unable to seek in the stream without actually computing the data). – The Vee Jan 02 '13 at 02:06
  • Too bad `SoftReferences` are broken on Android, they would seem to be the single best way out here. – The Vee Jan 02 '13 at 02:07
  • Take a look at Kryo http://code.google.com/p/kryo/ in particular, the Chunked Encoding features. The idea would be to use Kryo to build a chunked disk cache. I'm not sure if it will work on Android as I have not tried to use it on Android. But this wil give you some ideas. – Akos Cz Jan 02 '13 at 02:09
  • 1
    Look at http://www.google.com/patents?id=TpDLAQAAEBAJ and http://www.google.com/patents/US7716449 to get your creative juices flowing – Akos Cz Jan 02 '13 at 02:18