SoftReference gets garbage collected too early
Asked Answered
A

5

11

I'm on my way with implementing a caching mechanism for my Android application.

I use SoftReference, like many examples I've found. The problem is, when I scroll up or down in my ListView, the most of the images are already cleared. I can see in LogCat that my application is garbage collected everytime the application loads new images. That means that the most of the non-visible images in the ListView are gone.

So, everytime I scroll back to an earlier position (where I really downloaded images before) I have to download the images once again - they're not cached.

I've also researched this topic. According to Mark Murphy in this article, it seems that there is (or was?) a bug with the SoftReference. Some other results indicates the same thing (or the same result); SoftReferences are getting cleared too early.

Is there any working solution?

Amon answered 22/4, 2011 at 17:8 Comment(8)
too early? if there is a need for memory, it will be cleared. who's to say its too early? if the system wants to clear it, this is what softreference is for..Usquebaugh
Correct. But there is no need for more memory, since I can easily fit about 50 images in memory. But in order to avoid an OOM error I need to use this caching mechanism.Amon
i suggest you cache each image, that way when it is cleared, you don't have to fetch it from the web(unless it doesn't exist in cache)Usquebaugh
Well, that is beyond the actual statement in this question. I think that a caching mechanism without actually saving my images should work, like in the code above. Therefore, I'm asking if anyone else has solved this using this technique.Amon
@Viktor Lannér, I think you're answering your own question with this "in order to avoid an OOM error I need to use this caching mechanism". Soft references are cleared at the discretion of the GC, and the only guarantee is that they're all cleared before an OOM error is thrown. If you see OOM error without soft references there is obviously memory pressure. So the GC is acting as promised. Try reducing the size of your images and/or mitigating the effect of soft refs being cleared by also caching on disk.Rupee
@rlibby: Well, the OOM error hasn't appeared yet, so I think that there is no "memory pressure". Since I've seen other answers here on SO regarding this subject (although it's hard to figure it out), I think that there is a working solution without caching or reducing the size of my images.Amon
I had the same experience with DIY cache with SoftReferences. They got cleared during JVM idle time, without any pressing memory issue. There is no guarantee SR will be kept right until OOM; rather, GC may clean them as soon as it believes reasonable.Hospitalization
@road to yamburg: Yep, I'm pretty sure it is that way.Amon
M
16

SoftReference are the poor mans Cache. The JVM can hold those reference alive longer, but doesn't have to. As soon as there's no hard reference anymore, the JVM can garbage collect a the soft-referenced Object. The behavior of the JVM you're experiencing is correct, since the JVM doesn't have to hold such object longer around. Of course most JVMs try to keep the soft reference object alive to some degree.

Therefore SoftReferences are kind of a dangerous cache. If you really want to ensure a caching-behavior, you need a real cache. Like a LRU-cache. Especially if you're caching is performance-critical, you should use a proper cache.

Melli answered 22/4, 2011 at 17:18 Comment(2)
Clear answer! Thanks! I will look into the LRU-cache and see if it's what I'm looking for. But why doesn't the JVM hold the soft reference "a bit longer"? There is actually memory left...Amon
Because it doesn't have to. Your understanding of SR contract is incorrect. GC doesn't "want" to postpone cleaning up SRs up to OOM moment, because it may simply have no time to do it then without affecting applications' performance.Hospitalization
S
7

From Android Training site:

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. In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash.

More information in link.

We shoud use LruCache instead.

Sanctify answered 13/8, 2012 at 10:46 Comment(1)
Thanks! I will consider that next time!Amon
C
3

Cache each image on persistent storage instead of just in memory.

Commit answered 22/4, 2011 at 17:17 Comment(2)
Persistent storage for a transient cache? RIght. This is a solution. For some other problem.Hospitalization
It's not exactly clear that this needs to be a transient cache.Commit
A
1

Gamlor's answer is correct in your situtation. However, for additional information, see the GC FAQ, question 32.

The Java HotSpot Server VM uses the maximum possible heap size (as set by the -Xmx option) to calculate free space remaining.

The Java HotSpot Client VM uses the current heap size to calculate the free space.

This means that the general tendency is for the Server VM to grow the heap rather than flush soft references, and -Xmx therefore has a significant effect on when soft references are garbage collected.

Aminaamine answered 9/6, 2011 at 18:26 Comment(1)
Ideally Android would keep the soft references at least for a bit, but it takes the fact that you used a SoftReference to mean you don't mind if that data goes away and basically deletes it instantly. The JVM does this properly. Android basically eats anything it can with the garbage collector. So JVM FAQ is more than pointless the the above problem. The answer to which is basically use strong references.Finding
M
1

Jvm follows this simple equation to determine if a soft reference should get cleared:

interval <= free_heap * ms_per_mb

interval is duration between last gc cycle timestamp and the last access timestamp of soft reference. free heap is heap space available at that moment. ms_per_mb is milliseconds allocated to every MB available in heap. (Constant default 1000 ms)

If above equation is false, reference gets cleared.

So, even if you have a lot of free memory, if your soft references have not been accessed for an ample amount of time, they will get cleared.

-XX:SoftRefLRUPolicyMSPerMB= jvm arg can be used to tweak ms_per_mb constant.

Missy answered 31/7, 2020 at 14:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.