I want to use WeakReferences as part of an (android) bitmap-cache to be able to check when a bitmap isn't used anymore.
My cache has a maximum-size that is smaller than the Java heap-space. When a new bitmap would overflow the cache, it should let go of bitmaps that aren't needed anymore.
My question: When does the get()-method of a WeakReference return null?
As soon as there are no more strong-references to the object? (and GC hasn't occurred yet)
Or when the GC has run and determined that their are no more strong-references to the object?
If 2. is true than I could run into the situation that my cache could fill up and GC hasn't recently run for some reason.
Then even if I had already let go of references AFTER the last GC run, WeakReference#get() would still return the object and my cache wouldn't clear it out.
The answer is it depends on what version of Android you're using. Somewhere in the 2.3 timeframe, Android changed its handling or weak references. Previously, it deleted them when the GC ran. As of some version of 2.3 (2.3.3?) it started deleting them immediately upon the last strong reference going away. So in modern versions of Android, weak references are useless.
Before this change, weak references were used for caching. They no longer work. The correct way now is to use an LRUCache. If you need to support older versions, use the support library to backport the LRU cache.
After some searching, I think the change was made in 3.0, not 2.3. Still, the solution is the same.
The WeakReference is cleared as soon as the GC has determined that the object is weakly reachable.
This is close to your second case. However, weak reachability requires not just the absence of strong references, but also the absence of soft references.
From the Java package documentation for java.lang.ref:
Soft and weak references are automatically cleared by the collector before being added to the queues with which they are registered, if any.
...
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.
To cache bitmaps use SoftReference rather than Weak. GC would clear WeakReference as soon as it looses all its Strong and Soft references which might destroy the purpose of caching. SoftReference are cleared only if there is low memory.And it is guaranteed that the GC would be run before throwing a OOME.
As stated in the other answers, a WeakReference will return null once the pointed object has no more strong/soft references and the GC has reclaimed memory.
On a more general rule, I don't think Weak/SoftReferences are a good thing in an application. It makes your mix concerns :
Your application is about business logic
The JVM and Dalvik are about memory management and code optimisation.
When you start to use Weak/Soft references, you introduce memory-managed concerns within your application, which makes it harder to develop/debug/understand.
You might want to have a fixed-size (number of elements or bitmap size) LRU cache instead.
Hope that helps !
Related
Ok today I was in an interview and I have been coding Java for years. The interview said "Java garbage collection is a tricky one I had few friends who had struggled figuring out. How are you doing on that?". Was she trying to trick me? or is my entire life a lie and java does not have automatic garbage collection?
Because as far as i know java has automatic garbage collection and you can call System.gc() to collect some resources but this does not force the object to get destroyed. It is still decided by JVM.
Am I wrong?
Just because the garbage collection is automatic doesn't means you can just completely ignore the implications of object allocation and cleanup and how the GC works.
For many applications, especially simple ones, it will be fine to just let the GC do it's thing. Although even then you have to make sure you are not holding onto references longer than needed.
As your application becomes bigger and more complicated, especially if you are using any multi-threading, the impact the GC poses becomes more of a concern and it becomes more important to understand how everything is working in your code and what the GC is doing.
GC is automatic, yes.
But some practices related to GC may be subtle and so should be known and understood to avoid memory leak or undesirable behavior.
For example :finalize()
is called by the garbage collector on an object when garbage collection
determines that there are no more references to the object
according to the javadoc but in reality it could never be called.
Other example : GC collects remove the objects that are no referenced any longer but you could have a "heavy" object that is not any longer required but still referenced by a referenced object. So the heavy would not be elligible to be collected.
Using monitoring tools as JVisualVM shows sometimes some surprises and I say : Ah, this big object is still referenced here...
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Forcing Garbage Collection in Java?
Can I Force Garbage Collection in Java by any means?
System.gc() is just a suggestion.It's useless.
When I know for sure that some resources won't be used any more,why can't I force to clean them?
Just like delete() in C++ and free() in C?
When there are lots of resources that can't be reused,this can really suck the performance.All that we can do is sleep().
Any solutions?Thanks
Nope, System.gc() is as close as you can get. Java isn't C or C++, the JVM manages memory for you, so you don't have that kind of fine grained control. If you set objects you're no longer using to null, or loose all references, they will get cleaned up. And the GC is pretty smart, so it should take good care of you.
That said, if you are on a unix box, and force a thread dump (kill -3), it'll pretty much force garbage collection.
You shouldn't be trying to force GC - if you are running low on memory then you have a memory leak somewhere. Forcing GC at that point won't help, because if you are holding a reference to the object then it still won't be garbage collected.
What you need to do is solve the real problem, and make sure you are not holding references to objects you are not using any more.
Some common culprits:
Holding lots of references in a large object graph that never get cleared up. Either set references to null when you don't need them any more, or better still simplify your object graph so it doesn't need all the extra long-term references.
Caching objects in a hashmap or something similar that grows huge over time. Stop doing this, or use something like Google's CacheBuilder to create a proper soft reference cache.
Using String.intern() excessively on large numbers of different strings over time.
References with larger scope than they need. Are you using an instance variable when it could be a local variable, for example?
There is no way to explicitly instruct the JVM to collect garbage. This is only performed when the system needs the resources.
The only two actions I'm aware of to potentially get the GC running are the following:
As you stated, attempt to "suggest" that GC now would be a good time by called System.gc().
Set any references you are not using to the null reference to make the elements eligible for collection.
On my second point, see the answer here: Garbage collector in java - set an object null. In essence, if you don't make the objects you don't need available for garbage collection (by losing the reference you have to it) then there is no reason for the garbage collector to run, because it's unaware of any available garbage.
In addition, it's important to consider why/how those objects in memory are affecting performance:
Are you getting lots of OutOfMemoryExceptions? This could be resolved by point #2 and by increasing the available heap space for the JVM.
Have you done measurements to see that more objects in the JVM's allocated heap space makes a difference in performance? Determining when you could let references to objects go earlier could help reduce these issues.
I know that the GC collects objects that have no references pointing to the object in question, but what happens in the event of listener objects?
Suppose you have an AnimationDelegate that listens to data from a DataSupplier. When the DataSupplier recieves data and fires off the event to the AnimationDelegate, the delegate will then invalidate (/update/redraw etc...) a Graphic. Now say the screen is disabled, removed or, through various means, the graphic can no longer draw and is collected. The AnimationDelegate is still registered to the DataSupplier. How will the GC know to collect it? Should one unregister the delegate in the graphics finalize() method?
I'm afraid the answer won't fit the format :) Start with this article by Brian Goetz: he's a perfect person to read if you're interested in GC.
Basically, as soon as object is not reachable from active threads, it's collected. The actual algorithms vary even within one JVM, but the point stays the same: what's not reachable is a garbage. What's reachable is not a garbage. Easy.
GC will not collect the Graphic in your example, as it's reachable from AnimationDelegate, which in turn is reachable (via subscription) from DataSupplier which is supposed to be reachable from some active thread. So the answer will be: your assumptions are wrong; GC will not collect anything here.
To answer your question, unsubscribe everything you don't need.
As #rfeak rightfully says, finalize() is a big no-no. It's almost impossible to use it properly, and it's way too easy to use it wrong. That said,it's OK to use it as a backup solution when you need to free resources. But generally your application has to be able to work just fine even if finalize() never gets called.
It all depends on the JVM you're using and the GC. Most default GC from the JDK use the so called "tracing collectors", which simply start at a given root set of objects and trace all the objects reachable from that set. All the other objects in memory are seen as garbage and deleted. So circular references aren't really a problem unless one of the objects is reachable from the root set.
What is the root set of objects? Well if memory serves right roots can be found in: program registers, local variables in each thread's stack and static variables.
To see if your objects will be GC'd we would know more about the design of your application.
#Edit: Oh and I almost forgot: Memory Management in the JavaHotSpotâ„¢ Virtual Machine. This is a pretty good overview of how it all works.
It will only know if you have removed the references (nulled them out).
However, don't do this on finalize(). Finalize is bad bad bad. There should be other lifecycle methods available for cleaning up listener(observer) type objects.
By the way, observer pattern is notorious for creating memory leaks because the GC couldn't collect due to lingering references.
Here's my use case. We are trying to narrow down a potential memory leak in an application, and we are using a memory analysis tool to snapshot the heap so we can look for object instances and references. (In case it helps, we're using YourKit.)
This application makes extensive use of dynamic and CGLIB proxies, which end up storing tons of references to classes and classloaders in WeakHashMaps.
After our test case runs, we are expecting all hard references to object X and its classloader to be gone, but since there were many proxies involved in the test case in the end we have many weak/soft references left to it. (I can only find WeakHashMap references, but YourKit wraps both weak and soft references into one line item in the summary so I can't be sure I'm not missing a soft reference somewhere.)
This is true even after requesting a full GC from the JVM. (Using the sun 1.6.0_23 JDK in server mode.)
It seems as though the JVM admits there are only weak/soft references to these objects, but I can't get force it to GC these things to be 100% sure. (So, what I want is for this to disappear entirely from the heap and its classloader usage of permgen to also go away.)
Anyone know of a way to configure and/or force the JVM to dispose of objects only soft/weakly referenced?
Calling GC should always release all weakly-reachable objects (assuming the "request" made by calling System.gc is actually granted). If weak references are not getting cleared by GC, it means the objects are at least softly reachable.
Clearing soft references is trickier, as this is up to the JVM's discretion. The only way to guarantee clearing of softly-reachable objects is to cause an OutOfMemoryError to be thrown. This trick is demonstrated in this discussion.
I have a cache which has soft references to the cached objects. I am trying to write a functional test for behavior of classes which use the cache specifically for what happens when the cached objects are cleared.
The problem is: I can't seem to reliably get the soft references to be cleared. Simply using up a bunch of memory doesn't do the trick: I get an OutOfMemory before any soft references are cleared.
Is there any way to get Java to more eagerly clear up the soft references?
Found here:
"It is guaranteed though that all
SoftReferences will get cleared before
OutOfMemoryError is thrown, so they
theoretically can't cause an OOME."
So does this mean that the above scenario MUST mean I have a memory leak somewhere with some class holding a hard reference on my cached object?
The problem is: I can't seem to
reliably get the soft references to be
cleared.
This is not unique to SoftReferences. Due to the nature of garbage collection in Java, there is no guarantee that anything that is garbage-collectable will actually be collected at any point in time. Even with a simple bit of code:
Object temp = new Object();
temp = null;
System.gc();
there is no guarantee that the Object instantiated in the first line is garbage collected at this, or in fact any point. It's simply one of the things you have to live with in a memory-managed language, you're giving up declarative power over these things. And yes, that can make it hard to definitively test for memory leaks at times.
That said, as per the Javadocs you quoted, SoftReferences should definitely be cleared before an OutOfMemoryError is thrown (in fact, that's the entire point of them and the only way they differ from the default object references). It would thus sound like there is some sort of memory leak in that you're holding onto harder references to the objects in question.
If you use the -XX:+HeapDumpOnOutOfMemoryError option to the JVM, and then load the heap dump into something like jhat, you should be able to see all the references to your objects and thus see if there are any references beside your soft ones. Alternatively you can achieve the same thing with a profiler while the test is running.
There is also the following JVM parameter for tuning how soft references are handled:
-XX:SoftRefLRUPolicyMSPerMB=<value>
Where 'value' is the number of milliseconds a soft reference will remain for every free Mb of memory. The default is 1s/Mb, so if an object is only soft reachable it will last 1s if only 1Mb of heap space is free.
You can force all SoftReferences to be cleared in your tests with this piece of code.
If you really wanted to, you can call clear() on your SoftReference to clear it.
That said, if the JVM is throwing an OutOfMemoryError and your SoftReference has not been cleared yet, then this means that you must have a hard reference to the object somewhere else. To do otherwise would invalidate the contract of SoftReference. Otherwise, you are never guaranteed that the SoftReference is cleared: as long as there is still memory available, the JVM does not need to clear any SoftReferences. On the other hand, it is allowed to clear them next time it does a GC cycle, even if it doesn't need to.
Also, you can consider looking into WeakReferences since the VM tends to be more aggressive in clear them. Technically, the VM isn't ever required to clear a WeakReference, but it is supposed to clean them up next time it does a GC cycle if the object would otherwise be considered dead. If your are trying to test what happens when your cache is cleared, using WeakReferences should help your entries go away faster.
Also, remember that both of these are dependent on the JVM doing a GC cycle. Unfortunately, there is no way to guarantee that one of those ever happens. Even if you call System.gc(), the garbage collector may decide that it is doing just peachy and choose to do nothing.
In a typical JVM implementation (SUN) you need to trigger a Full GC more than once to get the Softreferences cleaned. The reason for that is because Softreferences require the GC to do more work, because for example of a mechanism that allows you to get notified when the objects are reclaimed.
IMHO using a lot of sofreferences in an application server is evil, because the developer has not much control over when they are released.
Garbage collection and other references like soft references are non deterministic this it's not really possible to reliable do stuff so that soft references are definitely cleared at that point so your test can judge how yourcache reacts. I would suggest you simulate the reference clearing in more definite way by mocking etc - your tests will be reproducable and more valuable rather than just Hopi g for the GC to clean up references. Using the latter approach is a really bad thing to do and willjust introduce additional problems rather than help you improve the quality of your cache and it's collaborating components.
From the documentation and my experience I'd say yes: you must have a reference somewhere else.
I'd suggest using a debugger that can show you all references to an object (such as Eclipse 3.4 when debugging Java 6) and just check when the OOM is thrown.
If you use eclipse, there is this tool named Memory Analyzer that makes heap dump debugging easier.
Does the cached object have a finalizer? The finalizer will create new strong references to the object, so even if the SoftReference is cleared the memory will not be reclaimed until a later GC cycle
If you have a cache which is a Map of SoftReferences and you want them cleared you can just clear() the map and they will all be cleaned up (including their references)