Cross-references and garbage collection - java

There is an application with an extensive object graph. This graph mainly consists of a set of subgraphs which are connected to the rest of the graph through the only reference. But internally each such subgraph has some number of cross-references among objects. Once in a while such a sub graph needs to be thrown away. Would it be enough just to set to null the only referece which points to that subgraph to make it eligible for garbage collection?
My concern is that internal cross-references may "protect" the entire subgraph from garbage collection. In other words, is the garbage collector wise enough to figure out that all references in a subgraph do not leave the boundaries of the subgraph and therefore entire subgraph can be purged.

As stated in this SO question, circular reference is well managed.
Java does not do reference counting, it does uses tracing garbage collection (for example mark-and-sweep, copying collection or a some combination thereof). If follows all the active references to find out what objects are "reachable" and then it cleans up everything else.
References in objects not themselves reachable don't affect reachability so it doesn't matter if they are null or not.
About the only case in which setting a reference to null might, conceivably, have a significant effect is in discarding a very large object in the middle of a long running method.
In that case, setting null to the reference of the graph will help making an island of isolation (even for internal circular references) as described in this article.
You will find more details about the unreachable state in The Truth About Garbage Collection:
Unreachable
An object enters an unreachable state when no more strong references to it exist.
When an object is unreachable, it is a candidate for collection.
Note the wording:
Just because an object is a candidate for collection doesn’t mean it will be immediately
collected. The JVM is free to delay collection until there is an immediate need for thememory being consumed by the object.
It’s important to note that not just any strong reference will hold an object in memory. These must be references that chain from a garbage collection root. GC roots are a special class of variable that includes:
Temporary variables on the stack (of any thread)
Static variables (from any class)
Special references from JNI native code
Circular strong references don’t necessarily cause memory leaks.
Consider a code creating two objects, and assigns them references to each other.
public void buidDog() {
Dog newDog = new Dog();
Tail newTail = new Tail();
newDog.tail = newTail;
newTail.dog = newDog;
}
Before the method returns, there are strong references from the temporary stack variables in the buildDog method pointing to both the Dog and the Tail.
After the buildDog method returns, the Dog and Tail both become unreachable from a root and are candidates for collection (although the VM might not actually collect these objects for an indefinite amount of time).

Yes - the garbage collector can cope with circular references etc.

The JVM operates on the notion of "islands of unreachability". If there is an unreachable 'island' of interconnected objects then that set of objects is eligible for garbage collection in its entirety.

Related

How to not reference an Object when it is not used so it gets deleted by GarbageCollection

I have an array list that will constantly have different amounts of items in it.
It won't be deleted when it's empty.
Can this cause memory leaks?
I see people saying to make something eligible for garbage collection you have to de-reference it. What does this mean?
An empty array is not a memory leak risk.
Memory leaks happen when a collection accepts unlimited references. It's hard to see how an empty list will be a problem.
An object that has a reference to an empty list will keep it in memory.
The garbage collector will mark an object as eligible for garbage collection when no other object refers to it. All references to that object have to be removed.
You can set reference to null to "de-reference" object. Like this for example:
Object o = new Object();
o = null;
In java when nothing points to the object (there is no reference to the object) then the object is "eligible" for garbage collector.
When it comes to memory leaks it really depends on your situation but it is possible to have some leaks due to not de-referencing.
Developers sometimes talk about "memory leaks" in Java. What they mean is that they have a lot of memory allocated that they no longer require, but in principle the application could reference if it wanted to. This is different from the "classical memory leak" which you would see in a language like 'C' where the application explicitly has to allocate an deallocate memory. As this question is about Java I won't concern myself with the "Classical Memory Leak", but just understand that the two are different
As #hdw3 correctly states, in Java an object is eligible for garbage collection if you have no reference to it. This is a specific case of a more general rule - an object is eligible for garbage collection if it can not be referenced in any way by your application. There is a subtle but important difference here...
Case 1
If you have a reference to object 'A' and that object has a reference to object 'B'. (This could be your ArrayList if contains a single item.) Neither object is eligible for garbage collection as the String can be referenced through the list.
As soon as you loose the referenced to your first object then neither object is accessible from your application, so both become eligible for garbage collection.
Case 2
Imagine you have a reference to object 'A' and that object has a reference to object 'B', AND object 'B' has a reference back to object 'A'. Objects 'A' and 'B' are both accessible so neither are not eligible for garbage collection.
As soon as you loose your reference to object 'A' then 'B' also becomes inaccessible. Both objects become eligible for garbage collection, even though they reference each other.
You can loose your reference to the object in a couple of different of ways.
The usual way is to simply exit a method that has the only reference to the object.
As #hdw3 points out reassign your reference so that it points to something
Something called "SoftReferences" exist, but you only need to worry about them if you are implementing large caches.
What you'll find is that in Java the Garbage Collector almost always does the right thing for you and you don't need to bother about memory too much.
The Java "Memory Leak" I mentioned earlier occurs if you've got a large structure you application no longer requires, but in theory the application could reference objects in that structure. For example you've got a massive List of Strings, you've finished processing them but haven't existed the method yet. This is when you'd assign your reference to null, to make ALL objects in the structure eligible for garbage collection

Two Object references point to each other

In objective C, there is a chance that two different references can point to each other.
But is this possible in Java? I mean, can two object references point to each other? If it's possible, when are they going to be garbage collected?
And, In case of nested classes, two objects (inner class's and outer class's) are linked to each other - how are these objects garbage collected?
I assume you are talking about circular references . Java's GC considers objects "garbage" if they aren't reachable through a chain starting at a GC root. Even though objects may point to each other to form a cycle, they're still eligible for GC if cut off from the root.
There are four kinds of GC roots in Java:
Local variables are kept alive by the stack of a thread. This is not a real object virtual reference and thus is not visible. For all intents and purposes, local variables are GC roots.
Active Java threads are always considered live objects and are therefore GC roots. This is especially important for thread local variables.
Static variables are referenced by their classes. This fact makes them de facto GC roots. Classes themselves can be garbage-collected, which would remove all referenced static variables. This is of special importance when we use application servers, OSGi containers or class loaders in general.
JNI References are Java objects that the native code has created as part of a JNI call. Objects thus created are treated specially because the JVM does not know if it is being referenced by the native code or not. Such objects represent a very special form of GC root.
You can also read here for more information.
Yes, you can do this. Like this:
class Pointy {
public Pointy other;
}
Pointy one = new Pointy();
Pointy two = new Pointy();
one.other = two;
two.other = one;
They're garbage collected when both objects are not pointed at by anything other than one another, or other objects which are "unreachable" from current running code. The Java garbage collectors are "tracing" garbage collectors, which means they can discover this sort of issue.
Conversely, reference-counted systems (like Objective C without its "modern" garbage collection -- I don't know what the default is) cannot normally detect this sort of issue, so the objects can be leaked.
Of course you can have objects reference each other. You could simply pass the this pointer in both objects to each other, which is perfectly valid.
However, that doesn't mean that the objects are still accessible from the GC root. Think of it as a (graph) tree. If you cut off a complete branch from the trunk, the whole branch is lost, no matter how many objects are involved or are maintaing references to each other.

What will GC do if there is a two level soft referenced object

I know in Java we have concept of soft reference. What if:
1) There is a soft reference "sf" refer to an object A
2) In object A, it has a strong reference refers to object B
3) object A & B are not referenced anywhere else.
By definition, object A and object B are both "softly reachable", right?
Then say we are running out of memory now, GC kicks in. Is it possible that GC will recycle object B but not object A?
If that's the case, later if we want to access object B through "sf", it will be null. How java avoid such case to happen?
I don't see any explain in java doc.
Then say we are running out of memory now, GC kicks in. Is it possible that GC will recycle object B but not object A?
No. The GC will not break strong references in reachable objects. (It will, of course break references in unreachable objects as part of the reclamation process. But you can't observe that happening ... because to observe it, you'd need the object to still be reachable.)
This is a consequence of this statement in the javadoc for the java.lang.ref package.
"Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways."
... where "the above ways" includes strong, soft, weak and phantom reachability.
The two highlighted words mean that eligibility for reclamation is a consequence of being in the unreachable state. Since none of the other states mention reclamation eligibility, we conclude that non-reachability is a precondition for reclamation.
This certainly aligns with common sense. If (hypothetically) the GC was allowed to "null out" strong references in reachable objects, it would be impossible for an application to safely work with objects after they had gotten into this state. (Consider the case where the nulled-out reference was in an instance of a library class ...)
I think a short introduction on how tracing GCs basically work should clear things up.
A tracing GC (the ones used in Java and .NET all fall into that category) has a set of so called root pointers, those are global variables (in java that means static variables of classes) and all live variables in the stackframes. The GC traverses these and marks all objects that are alive, i.e. reachable through references from at least one of the root pointers. When it has finished, all live variables have been marked and the rest can be garbage collected.
A soft reference now can be handled in two different ways: a) we follow the soft reference and mark all objects in it or b) we don't. What exactly happens is at the mercy of the given JVM implementation, but after that has been decided there's no other difference.
Hence there are two possible scenarios:
The GC follows the soft reference to A in which case none of the two objects will be GCed.
The GC doesn't follow the soft reference to A (and there are no hard references to it). A is GCed, B is GCed if no live object has a reference to it.
From the docs:
"An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference."
"An object is strongly reachable if it can be reached by some thread without traversing any reference objects"
I think thats pretty clear. B is softly reachable because it is only reachable by traversing a soft reference.
Said Docs

Garbage collector in java - set an object null

Lets assume, there is a Tree object, with a root TreeNode object, and each TreeNode has leftNode and rightNode objects (e.g a BinaryTree object)
If i call:
myTree = null;
what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??
Garbage collection in Java is performed on the basis of "reachability". The JLS defines the term as follows:
"A reachable object is any object that can be accessed in any potential continuing computation from any live thread."
So long as an object is reachable1, it is not eligible for garbage collection.
The JLS leaves it up to the Java implementation to figure out how to determine whether an object could be accessible. If the implementation cannot be sure, it is free to treat a theoretically unreachable object as reachable ... and not collect it. (Indeed, the JLS allows an implementation to not collect anything, ever! No practical implementation would do that though2.)
In practice, (conservative) reachability is calculated by tracing; looking at what can be reached by following references starting with the class (static) variables, and local variables on thread stacks.
Here's what this means for your question:
If i call: myTree = null; what really happens with the related TreeNode objects inside the tree? Will be garbage collected as well, or i have to set null all the related objects inside the tree object??
Let's assume that myTree contains the last remaining reachable reference to the tree root.
Nothing happens immediately.
If the internal nodes were previously only reachable via the root node, then they are now unreachable, and eligible for garbage collection. (In this case, assigning null to references to internal nodes is unnecessary.)
However, if the internal nodes were reachable via other paths, they are presumably still reachable, and therefore NOT eligible for garbage collection. (In this case, assigning null to references to internal nodes is a mistake. You are dismantling a data structure that something else might later try to use.)
If myTree does not contain the last remaining reachable reference to the tree root, then nulling the internal reference is a mistake for the same reason as in 3. above.
So when should you null things to help the garbage collector?
The cases where you need to worry are when you can figure out that that the reference in some cell (local, instance or class variable, or array element) won't be used again, but the compiler and runtime can't! The cases fall into roughly three categories:
Object references in class variables ... which (by definition) never go out of scope.
Object references in local variables that are still in scope ... but won't be used. For example:
public List<Pig> pigSquadron(boolean pigsMightFly) {
List<Pig> airbornePigs = new ArrayList<Pig>();
while (...) {
Pig piggy = new Pig();
...
if (pigsMightFly) {
airbornePigs.add(piggy);
}
...
}
return airbornePigs.size() > 0 ? airbornePigs : null;
}
In the above, we know that if pigsMightFly is false, that the list object won't be used. But no mainstream Java compiler could be expected to figure this out.
Object references in instance variables or in array cells where the data structure invariants mean that they won't be used. #edalorzo's stack example is an example of this.
It should be noted that the compiler / runtime can sometimes figure out that an in-scope variable is effectively dead. For example:
public void method(...) {
Object o = ...
Object p = ...
while (...) {
// Do things to 'o' and 'p'
}
// No further references to 'o'
// Do lots more things to 'p'
}
Some Java compilers / runtimes may be able to detect that 'o' is not needed after the loop ends, and treat the variable as dead.
1 - In fact, what we are talking about here is strong reachability. The GC reachability model is more complicated when you consider soft, weak and phantom references. However, these are not relevant to the OP's use-case.
2 - In Java 11 there is an experimental GC called the Epsilon GC that explicitly doesn't collect anything.
They will be garbage collected unless you have other references to them (probably manual). If you just have a reference to the tree, then yes, they will be garbage collected.
You can't set an object to null, only a variable which might contain an pointer/reference to this object. The object itself is not affected by this. But if now no paths from any living thread (i.e. local variable of any running method) to your object exist, it will be garbage-collected, if and when the memory is needed. This applies to any objects, also the ones which are referred to from your original tree object.
Note that for local variables you normally not have to set them to null if the method (or block) will finish soon anyway.
myTree is just a reference variable that previously pointed to an object in the heap. Now you are setting that to null. If you don't have any other reference to that object, then that object will be eligible for garbage collection.
To let the garbage collector remove the object myTree just make a call to gc() after you've set it to null
myTree=null;
System.gc();
Note that the object is removed only when there is no other reference pointing to it.
In Java, you do not need to explicitly set objects to null to allow them to be GC'd. Objects are eligible for GC when there are no references to it (ignoring the java.lang.ref.* classes).
An object gets collected when there are no more references to it.
In your case, the nodes referred to directly by the object formally referenced by myTree (the root node) will be collected, and so on.
This of course is not the case if you have outstanding references to nodes outside of the tree. Those will get GC'd once those references go out of scope (along with anything only they refer to)

What's the difference between SoftReference and WeakReference in Java?

What's the difference between java.lang.ref.WeakReference and java.lang.ref.SoftReference ?
From Understanding Weak References, by Ethan Nicholas:
Weak references
A weak reference, simply put, is a
reference that isn't strong enough to
force an object to remain in memory.
Weak references allow you to leverage
the garbage collector's ability to
determine reachability for you, so you
don't have to do it yourself. You
create a weak reference like this:
WeakReference weakWidget = new WeakReference(widget);
and then
elsewhere in the code you can use
weakWidget.get() to get the actual
Widget object. Of course the weak
reference isn't strong enough to
prevent garbage collection, so you may
find (if there are no strong
references to the widget) that
weakWidget.get() suddenly starts
returning null.
...
Soft references
A soft reference is exactly like a
weak reference, except that it is less
eager to throw away the object to
which it refers. An object which is
only weakly reachable (the strongest
references to it are WeakReferences)
will be discarded at the next garbage
collection cycle, but an object which
is softly reachable will generally
stick around for a while.
SoftReferences aren't required to
behave any differently than
WeakReferences, but in practice softly
reachable objects are generally
retained as long as memory is in
plentiful supply. This makes them an
excellent foundation for a cache, such
as the image cache described above,
since you can let the garbage
collector worry about both how
reachable the objects are (a strongly
reachable object will never be removed
from the cache) and how badly it needs
the memory they are consuming.
And Peter Kessler added in a comment:
The Sun JRE does treat SoftReferences differently from WeakReferences. We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. One detail: the policy for the "-client" and "-server" JRE's are different: the -client JRE tries to keep your footprint small by preferring to clear SoftReferences rather than expand the heap, whereas the -server JRE tries to keep your performance high by preferring to expand the heap (if possible) rather than clear SoftReferences. One size does not fit all.
Weak references are collected eagerly. If GC finds that an object is
weakly reachable (reachable only through weak references), it'll clear the
weak references to that object immediately. As such, they're good for
keeping a reference to an object for which your program also keeps
(strongly referenced) "associated information" somewere, like cached
reflection information about a class, or a wrapper for an object, etc.
Anything that makes no sense to keep after the object it is associated
with is GC-ed. When the weak reference gets cleared, it gets enqueued in a
reference queue that your code polls somewhere, and it discards the
associated objects as well. That is, you keep extra information about an
object, but that information is not needed once the object it refers to
goes away. Actually, in certain situations you can even subclass
WeakReference and keep the associated extra information about the object
in the fields of the WeakReference subclass. Another typical use of
WeakReference is in conjunction with Maps for keeping canonical instances.
SoftReferences on the other hand are good for caching external, recreatable resources
as the GC typically delays clearing them. It is guaranteed though that all
SoftReferences will get cleared before OutOfMemoryError is thrown, so they
theoretically can't cause an OOME[*].
Typical use case example is keeping a parsed form of a contents from a
file. You'd implement a system where you'd load a file, parse it, and keep
a SoftReference to the root object of the parsed representation. Next time
you need the file, you'll try to retrieve it through the SoftReference. If
you can retrieve it, you spared yourself another load/parse, and if the GC
cleared it in the meantime, you reload it. That way, you utilize free
memory for performance optimization, but don't risk an OOME.
Now for the [*]. Keeping a SoftReference can't cause an OOME in itself. If
on the other hand you mistakenly use SoftReference for a task a WeakReference is meant
to be used (namely, you keep information associated with an Object somehow
strongly referenced, and discard it when the Reference object gets
cleared), you can run into OOME as your code that polls the ReferenceQueue
and discards the associated objects might happen to not run in a timely
fashion.
So, the decision depends on usage
- if you're caching information that is expensive to construct, but
nonetheless reconstructible from other data, use soft references
- if you're keeping a reference to a canonical instance of some data, or
you want to have a reference to an object without "owning" it (thus
preventing it from being GC'd), use a weak reference.
In Java; order from strongest to weakest, there are: Strong, Soft, Weak and Phantom
A Strong reference is a normal reference that protects the referred object from collection by GC. i.e. Never garbage collects.
A Soft reference is eligible for collection by garbage collector, but probably won't be collected until its memory is needed. i.e. garbage collects before OutOfMemoryError.
A Weak reference is a reference that does not protect a referenced object from collection by GC. i.e. garbage collects when no Strong or Soft refs.
A Phantom reference is a reference to an object is phantomly referenced after it has been finalized, but before its allocated memory has been reclaimed.
Source
Analogy: Assume a JVM is a kingdom, Object is a king of the kingdom, and GC is an attacker of the kingdom who tries to kill the king(object).
When King is Strong, GC can not kill him.
When King is Soft, GC attacks him but King rule the kingdom with protection until resource are available.
When King is Weak, GC attacks him but rule the kingdom without protection.
When king is Phantom, GC already killed him but king is available via his soul.
Weak Reference
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html
Principle: weak reference is related to garbage collection. Normally, object having one or more reference will not be eligible for garbage collection.
The above principle is not applicable when it is weak reference. If an object has only weak reference with other objects, then its ready for garbage collection.
Let's look at the below example: We have an Map with Objects where Key is reference a object.
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> aMap = new
HashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
System.out.println("Size of Map" + aMap.size());
}
}
Now, during the execution of the program we have made emp = null. The Map holding the key makes no sense here as it is null. In the above situation, the object is not garbage collected.
WeakHashMap
WeakHashMap is one where the entries (key-to-value mappings) will be removed when it is no longer possible to retrieve them from the Map.
Let me show the above example same with WeakHashMap
import java.util.WeakHashMap;
public class Test {
public static void main(String args[]) {
WeakHashMap<Employee, EmployeeVal> aMap =
new WeakHashMap<Employee, EmployeeVal>();
Employee emp = new Employee("Vinoth");
EmployeeVal val = new EmployeeVal("Programmer");
aMap.put(emp, val);
emp = null;
System.gc();
int count = 0;
while (0 != aMap.size()) {
++count;
System.gc();
}
System.out.println("Took " + count
+ " calls to System.gc() to result in weakHashMap size of : "
+ aMap.size());
}
}
Output: Took 20 calls to System.gc() to result in aMap size of : 0.
WeakHashMap has only weak references to the keys, not strong references like other Map classes. There are situations which you have to take care when the value or key is strongly referenced though you have used WeakHashMap. This can avoided by wrapping the object in a WeakReference.
import java.lang.ref.WeakReference;
import java.util.HashMap;
public class Test {
public static void main(String args[]) {
HashMap<Employee, EmployeeVal> map =
new HashMap<Employee, EmployeeVal>();
WeakReference<HashMap<Employee, EmployeeVal>> aMap =
new WeakReference<HashMap<Employee, EmployeeVal>>(
map);
map = null;
while (null != aMap.get()) {
aMap.get().put(new Employee("Vinoth"),
new EmployeeVal("Programmer"));
System.out.println("Size of aMap " + aMap.get().size());
System.gc();
}
System.out.println("Its garbage collected");
}
}
Soft References.
Soft Reference is slightly stronger that weak reference. Soft reference allows for garbage collection, but begs the garbage collector to clear it only if there is no other option.
The garbage collector does not aggressively collect softly reachable objects the way it does with weakly reachable ones -- instead it only collects softly reachable objects if it really "needs" the memory. Soft references are a way of saying to the garbage collector, "As long as memory isn't too tight, I'd like to keep this object around. But if memory gets really tight, go ahead and collect it and I'll deal with that." The garbage collector is required to clear all soft references before it can throw OutOfMemoryError.
The only real difference between a soft reference and a weak reference is that
the garbage collector uses algorithms to decide whether or not to
reclaim a softly reachable object, but always reclaims a weakly
reachable object.
SoftReference is designed for caches. When it is found that a WeakReference references an otherwise unreachable object, then it will get cleared immediately. SoftReference may be left as is. Typically there is some algorithm relating to the amount of free memory and the time last used to determine whether it should be cleared. The current Sun algorithm is to clear the reference if it has not been used in as many seconds as there are megabytes of memory free on the Java heap (configurable, server HotSpot checks against maximum possible heap as set by -Xmx). SoftReferences will be cleared before OutOfMemoryError is thrown, unless otherwise reachable.
This article can be super helpful to understand strong, soft, weak and phantom references.
To give you a summary,
If you only have weak references to an object (with no strong references), then the object will be reclaimed by GC in the very next GC cycle.
If you only have soft references to an object (with no strong references), then the object will be reclaimed by GC only when JVM runs out of memory.
So you can say that, strong references have ultimate power (can never be collected by GC)
Soft references are powerful than weak references (as they can escape GC cycle until JVM runs out of memory)
Weak references are even less powerful than soft references (as they cannot excape any GC cycle and will be reclaimed if object have no other strong reference).
Restaurant Analogy
Waiter - GC
You - Object in heap
Restaurant area/space - Heap space
New Customer - New object that wants table in restaurant
Now if you are a strong customer (analogous to strong reference), then even if a new customer comes in the restaurant or what so ever happnes, you will never leave your table (the memory area on heap). The waiter has no right to tell you (or even request you) to leave the restaurant.
If you are a soft customer (analogous to soft reference), then if a new customer comes in the restaurant, the waiter will not ask you to leave the table unless there is no other empty table left to accomodate the new customer. (In other words the waiter will ask you to leave the table only if a new customer steps in and there is no other table left for this new customer)
If you are a weak customer (analogous to weak reference), then waiter, at his will, can (at any point of time) ask you to leave the restaurant :P
The six types of object reachability states in Java:
Strongly reachable objects - GC will not collect (reclaim the memory occupied by) this kind of object. These are reachable via a root node or another strongly reachable object (i.e. via local variables, class variables, instance variables, etc.)
Softly reachable objects - GC may attempt to collect this kind of object depending on memory contention. These are reachable from the root via one or more soft reference objects
Weakly reachable objects - GC must collect this kind of object. These
are reachable from the root via one or more weak reference objects
Resurrect-able objects - GC is already in the process of collecting these objects. But they may go back to one of the states - Strong/Soft/Weak by the execution of some finalizer
Phantomly reachable object - GC is already in the process of collecting these objects and has determined to not be resurrect-able by any finalizer (if it declares a finalize() method itself, then its finalizer will have been run). These are reachable from the root via one or more phantom reference objects
Unreachable object - An object is neither strongly, softly, weakly, nor phantom reachable, and is not resurrectable. These objects are ready for reclamation
For more details: https://www.artima.com/insidejvm/ed2/gc16.html « collapse
The Only Real Difference
Per the doc, loose WeakReferences must be cleared by a running GC.
Per the doc, loose SoftReferences must be cleared before OOM is thrown.
That's the only real difference. Everything else is not part of the contract. (I'll assume the latest docs are contractual.)
SoftReferences are useful. Memory-sensitive caches use SoftReferences, not WeakReferences.
The only proper use of WeakReference is to observe the GC run. You do this by creating a new WeakReference whose object immediately goes out of scope, then try to get null out of weak_ref.get(). When it's null, you learn that between this duration, the GC ran.
As for incorrect use of WeakReference, the list is endless:
a lousy hack to implement priority-2 softreference such that you don't have to write one, yet it doesn't work as expected because the cache would be cleared on every GC run, even when there is spare memory. See https://stackoverflow.com/a/3243242/632951 for phails. (Besides, what if you need more than 2 levels of cache priority? You'd still gotta need a real library for it.)
a lousy hack to associate data with an object of an existing class, yet it creates a memory leak (OutOfMemoryError) when your GC decides to take a break after your weakreferences are created. Besides, it's beyond ugly: A better approach is to use tuples.
a lousy hack to associate data with an object of an existing class, where the class has the nerve to make itself non-subclassable, and is used in an existing function code which you need to call. In such a case, the proper solution is to either edit the class and make it subclassable, or edit the function and make it take an interface instead of a class, or use an alternative function.
To give an in-action memory usage aspect, I did an experiment with Strong, Soft, Weak & Phantom references under heavy load with heavy objects by retaining them till end of program. Then monitored heap usage & GC behavior. These metrics may vary case by case basis but surely gives high level understanding. Below are findings.
Heap & GC Behavior under heavy load
Strong/Hard Reference - As program continued, JVM couldn't collect retained strong referenced object. Eventually ended up in "java.lang.OutOfMemoryError: Java heap space"
Soft Reference - As program continued, heap usage kept growing, but OLD gen GC happened hen it was nearing max heap. GC started bit later in time after starting program.
Weak Reference - As program started, objects started finalizing & getting collected almost immediately. Mostly objects got collected in young generation garbage collection.
Phantom Reference - Similar to weak reference, phantom referenced objects also started getting finalized & garbage collected immediately. There were no old generation GC & all objects were getting collected in young generation garbage collection itself.
You can get more in depth graphs, stats, observations for this experiment here.
One should be aware that a weakly referenced object will only get collected when it has ONLY weak reference(s). If it has so much as one strong reference, it does not get collected no matter how many weak references it has.
WeakReference: objects that are only weakly referenced are collected at every GC cycle (minor or full).
SoftReference: when objects that are only softly referenced are collected depends on:
-XX:SoftRefLRUPolicyMSPerMB=N flag (default value is 1000, aka 1 second)
Amount of free memory in the heap.
Example:
heap has 10MB of free space (after full GC);
-XX:SoftRefLRUPolicyMSPerMB=1000
Then object which is referenced only by SoftReference will be collected if last time when it was accessed is greater then 10 seconds.

Categories

Resources