2

Is there a reliable approach to empty the cache before the memory is full? Or even better limit the cache according to current available "actual" free memory (hard-referenced objects)?

A soft referenced cache is not a good idea due to high GC penalty, once hit the limit all cache entries need to be reloaded.

Also the value runtime.freeMemory() is not that reliable for my purpose because even if it is too low, after the next GC cycle there might be plenty of free space so it's not a good indication of the actual used memory.

I tried to figure out how much memory each primitive time would consume so I would know the actual memory usage of the cache and put a limit on it, but couldn't find a reliable way to figure out how much memory would be used to store a String reference of size n.

Srinivas
  • 1,780
  • 1
  • 14
  • 27
danial
  • 4,058
  • 2
  • 32
  • 39
  • 3
    There isn't a reliable metric based on the `length()` of a String as different strings can share the same backing `char[]` - `"This is a very long string".substring(5,2)` is the string `is` but it holds a reference to the "very long" `char[]`. – Ian Roberts Jan 07 '13 at 09:52
  • 1
    Answers here might be able to give an idea. http://stackoverflow.com/questions/13855013/understanding-java-memory-management – Michael 'Maik' Ardan Jan 07 '13 at 09:54

3 Answers3

2

Have two or three collections. If you want degrading service with memory availability you can have.

  • a map on the most recent entries, e.g. LinkedHashMap.
  • a map of soft references.
  • a map of weak references.

You can control how large each map should be with the knowledge that weak references can be cleared after a minor collection, soft references will be cleared if needed, and the strong references map has the core data which will always be retained.

BTW: If you are hitting your memory limit often, you should consider buying more memory up to about 32 GB per JVM. You can buy 32 GB for less than $200.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • How would this make a difference? How do I make sure the cache will not cause OutOfMemmoryError? My application is running on GAE cloud server so adding more memory is not that cheap. – danial Jan 07 '13 at 13:31
  • The difference is; You can have a small number entries cached as a minimum and you will not get an OOME unless this small number is still too much i.e. your application was about to die anyway. It is a shame the cloud providers haven't keep up with newer technologies. My 8 year old has 8 GB in his PC as it cost me £24 and buying 4 GB didn't make much sense. – Peter Lawrey Jan 07 '13 at 14:02
  • The best way to avoid OOME is to reduce you memory consumption. To do that you need to memory profile your application with VisualVM or ideally a commercial profiler. – Peter Lawrey Jan 07 '13 at 14:02
2

Try one of the more recent Oracle 1.7 incarnations. They should offer a GarbageCollectorMXBean and GarbageCollectionNotificationInfo. Use that to monitor the amount of used/unused memory after each GC cycle. There is some sample code here. You can then use a multi-level cache as suggested by Peter to clean out the outer level when memory is tight, but retain the smaller first-level cache.

Ralf H
  • 1,392
  • 1
  • 9
  • 17
  • Unfortunately I want it to be GAE compatible which does not support Java 1.7, but seems like that's the way to go in the future if querying the managed bean is fast enough. – danial Jan 08 '13 at 01:34
1

I would suggest that the simplest solution would be to change your references to weak references. This way the references can still finalized and garbage collected when all strong references have gone out of scope.

See: http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html

jlaw90
  • 11
  • 1
  • As I mentioned in my question the problem with soft/weak references is that they will be all wiped out once the memory is short at any time making all the cache become empty, and it would be very expensive to rebuild the whole map. I want it to be smarted just empty enough of the cache to free up some space or just keep the size of the map bellow that threshold. – danial Jan 07 '13 at 13:29