Backstory
In a library that I maintain we have an internal map keeping track of our cache.
Users of the library are interested in having list access to this map, however we can only provide this by copying its contents (thread-safety reasons).
The idea is to cache this list when it is first accessed without having much memory overhead on a second access.
To illustrate:
List<Bob> list = cache.asList();
List<Bob> otherList = cache.asList(); // use from cache, if still available
The problem is, we don't want to keep this list forever if its not needed anymore. Since java uses GC we thought it would be appropriate to use a WeakReference for this, to allow using it if its not collected.
Question
If I have a WeakReference<List<Bob>> stored inside my class, what happens if one of the elements becomes weakly reachable (which implies the list is weakly reachable)? Is it possible that the GC decides to just collect the element inside the list or would it look for all other weakly reachable objects referencing it and also collect them, in this case the list?
The problem would be, if the GC collected an element of the list and we then try to access the list again (if thats even possible) what would happen?
Clarifications
I'm not interested in the reachability of the list, I know that the list is inside the WeakReference and that the elements are irrelevant to its reachability. I care about a specific state, in which both the list and an element of the list are weakly reachable and whether it is possible that the GC only collects the element but not the list itself. What exactly does the GC do in this specific scenario?
As long as the List itself is not weakly reachable its elements will not be either. (Assuming the list implementation itself does not use weak references or similar)
So there is no problem with having the list cached with a weak reference because it would either be garbage collected completely or not at all.
In provided case (WeakReference<List<Something>>) you have only such possible scenario:
public class Test {
private WeakReference<List<String>> listWeakReference;
public Test(final WeakReference<List<String>> listWeakReference) {
this.listWeakReference = listWeakReference;
}
public static void main(String[] args) {
List<String> testList = Arrays.asList("a", "b", "c");
Test test = new Test(new WeakReference<>(testList));
// Initial check
System.out.println(test.listWeakReference.get());
// Call gc and check
System.gc();
System.out.println(test.listWeakReference.get());
// Remove reference and call gc
testList = null;
System.gc();
System.out.println(test.listWeakReference.get());
}
}
Firstly SoftReference is better for caches, and even that isn't very good.
WeakReference may be released immediately the reference becomes weakly reachable. However, it might not do that until sometime into execution - i.e. it doesn't happen during extensive testing, but it does in production. Fun times. NetBeans used to do this in its caching of files. Of course the rest of the code was expecting the caching so grabbed and released references with incredible frequency. After sometime using the application it would suddenly hammer file I/O and become unusable.
For best performance you need to explicitly estimate how much memory the process is using and release as necessary. Not easy.
Back to the question. Collection of contents of WeakReference (and SoftReference is a two phase operation. The first phase just clears the Reference (and queues if you are using that). The associated memory is not collected. The memory may be resurrected through a finaliser. The WeakReference is forever cleared and queued, it does not reset. Only when an object is completely unreachable can the associated memory be collected as a separate phase.
Fear not, Java is memory-safe (bugs excepted).
Related
I'm reading the Effective Java book and its saying that eliminating obsolete reference is one of best way to avoid memory leaks. according to the below program, by doing -> elements[size] = null; its eliminating obsolete references in that program.
My problem here what is the advantage of doing elements[size] = null;. Any other program can use that freed memory location? Or is it garbage collected?
According to my understanding the array is already allocated the memory for its size. Even we do elements[size] = null; anyone can't use that freed memory location until you do elements = null;. Please someone tell me what is advantage of doing elements[size] = null; here.
public Object pop() {
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elements[size] = null; // Eliminate obsolete reference
return result;
}
My problem here what is the advantage of doing elements[size] = null;.
Here obsolete references refer to object references not required any longer for the program.
You want that unnecessary objects to be free to consume only memory that your program need. Generally it is done for the good working of the current application.
Any other program can use that freed memory location?
Theoretically yes but it also depends on the JVM memory options used. You don't generally focus on it.
elements[size] = null and elements = null; don't have at all the same intention and the same effects.
In the context of the book, elements is a structural intern of a class.
The idea is that some elements of the array may be stale and not required any longer after some removal operations.
The first one (elements[size] = null) will make the object of the array element located at the size index to be eligible to be GC if no other objects reference .
But the second one (elements = null) is much more. It will make all elements of the array to be eligible to be GC if no other objects reference it.
There are two cases we have to distinguish:
The outer object is "teared down" somehow, so it closes any open resource and also "voluntarily" releases all objects it had referred to. This s simply the explicit way of telling the jvm that the corresponding refence is "gone". You make it easier for the gc to understand: the corresponding object is eligible for garbage collection. Of course, that only has that effect if there are no other references to the same object elsewhere. And beyond: doing so isn't really required, the jvm/gc must of course be able to detect any eligible object all by itself.
But nullifying makes sense for refences that exist for longer periods of time, pointing to different objects over that time span. Like a container, such as the stack class in the underlying example. A container must forget about objects it referenced to when they get "removed". Otherwise you create a memory leak!
What happens here?
Let's imagine, elements is a 20-elements Object array (elements = new Object[20];), and has been filled with 18 BigInteger instances, the remaining two places being null.
So the heap now contains 18 BigInteger instances and a 20-elements Object[] array. The garbage collector won't reclaim any of these instances, and that's okay as you'll most probably use them later (via the pop() method).
Now you call the pop() method to get the BigInteger most recently added to the array. Let's assume you just want to print it and then forget it, so in your overall application that number isn't needed any more, and you'd expect the garbage collector to reclaim it. But that won't happen unless you do the null assignment
elements[size] = null; // Eliminate obsolete reference
Why that?
As long as you store the reference to an object in some accessible place, the garbage collector believes that you'll still need the object later.
As long as elements[17] still refers to the BigInteger, it can potentially be accessed by your program, so it can't be reclaimed. If elements[17] points to null, the BigInteger that used to be there isn't accessible via elements any more and can be reclaimed by the garbage collector (if no other part of your code still uses it).
Conclusion
It's only worth thinking about "obsolete references" if you have a long-living storage structure that contains fat objects, and you can tell at some point in time that you won't need one of the stored objects any more. As you won't need this object any more, you can now re-assign the storage with null, and then the GC no longer believes you still need the object and is able to reclaim the storage space.
Say I do something like this:
List<Stuff> methodA() {
List<Stuff> all_the_stuff_to_do = new ArrayList<>();
all_the_stuff_to_do.add(new Stuff("important"));
all_the_stuff_to_do.add(new Stuff("not important"));
return all_the_stuff_to_do;
}
List<Stuff> methodB() {
List<Stuff> important_stuff_to_do = new ArrayList<>();
Stuff important = methodA().get(0);
// at this point Stuff("not important") is not reachable anymore
// since I have no reference to the list that contains it left
important_stuff_to_do.add(important);
return important_stuff_to_do;
}
void methodC() {
... do a happydance ...
List<Stuff> stuff_to_do = methodB();
... look sad because now I got important stuff to do ...
}
***** EDIT *****
Better clarification and simplified code
To Clarify:
When exiting methodA() I got a reference of a list with two objects Stuff("important") and Stuff("not important")
I add the reference to Stuff("important") to a list in methodB().
At this point the Object Stuff("not important") is not reachable anymore.
Also the List in methodA() is not reachable anymore.
But the List still contains a reference to an Object that is indeed reachable, namely Stuff("important").
When will the all_the_stuff_to_do List be cleared and when the Stuff("not important") Object?
Will it be directly after the Call to MethodA? Or will it be at the end of MethodB? Or never since it contains a reference to the Stuff("important") Object that is still active till the end of the program?
Will (all_the_stuff_to_do be garbage collected) directly after the Call to MethodA?
Or will it be at the end of MethodB? Or never since it contains a reference to the Stuff("important") Object that is still active till the end of the program?
Garbage collection is generally done on a low priority thread. If nothing else is being done, the garbage collector may run.
If the VM is low on, or out of, memory, the garbage collector may run immediately as the highest priority thread, since it needs to recover memory for the program's immediate need.
So, will it be collected directly after the call to MethodA? No. Will it get collected after the call to get(0)? Possible, but unlikely. At the end of MethodB? Possible, but unlikely. Still active at the end of the program? Possible, but only likely if the program never ran out of memory and never became idle.
The fact that the list contains a copy of "Stuff("important") Object" is irrelevant to whether the list gets collected. If no accessible objects reference the list, the list is eligible for garbage collection.
Will the list get #clear()'d during collection? No, there is no need. If it was a user defined collection, the clear method could do anything, including add another reference to the list, which would mess up the garbage collection. Instead, it is just collected, and objects the list refer to are referenced one less time. That include "Stuff("important") Object" ... It's reference count will get decremented, but since a reference still exists, it won't be cleared.
The collection contains references to the objects that you have added. Until that is no longer reachable or you remove the objects from the collection, they will be reachable. Can you think of a way programs could work reliably if it were otherwise?
In your scenario new Stuff("important") here new keyword is responsible to making an object and reference of this Stuff Object hold by the collection List <Stuff> important_stuff_to_do. Now this collection will hold the reference of the two object that you made .
As per Collection definition all we know that Collection is a group of multiple Object of same type of Objects as a single Entity.
So, No Garbage Collection will be perform because here these two objects are still reachable.
new Stuff("important")
new Stuff("not important")
Note:- Garbage Collection performs only objects which is completely unreachable (One kind of Orphan). Here No Object is getting orphan because Collection never makes the copy / cloing of the objects which is added .
Conclusion :- No Garbage will be performed in this scenario. Thank you
With the following function:
Collection#clear
how can I attempt to reclaim memory that could be freed from an invocation? Code sample:
public class Foo
{
private static Collection<Bar> bars;
public static void main(String[] args){
bars = new ArrayList<Bar>();
for(int i = 0; i < 100000;i++)
{
bars.add(new Bar());
}
bars.clear();
//how to get memory back here
}
}
EDIT
What I am looking for is similar to how ArrayList.remove reclaims memory by copying the new smaller array.
It is more efficient to only reclaim memory when you need to. In this case it is much simpler/faster to let the GC do it asynchronous when there is a need to do. You can give the JVM a hint using System.gc() but this is likely to be slower and complicate your program.
how ArrayList.remove reclaims memory by copying the new smaller array.
It doesn't do this. It never shrinks the array, nor would you need to.
If you really need to make the collection smaller, which I seriously doubt, you can create a new ArrayList which has a copy of the elements you want to keep.
bars= null ;
would be the best. clear doesn't guarantee to release any memory, only to reset the logical contents to "empty".
In fact, bars= null ; doesn't guarantee that memory will be immediately released. However, it would make the object previously pointed by bars and all its dependents "ready for garbage collection" ("finalization", really, but let's keep this simple). If the JVM finds itself needing memory, it will collect these objects (other simplification here: this depends on the exact garbage collection algorithm the JVM is configured to use).
You can't.
At some point after there are no more references to the objects, the GC will collect them for you.
EDIT: To force the ArrayList to release its reference to the giant empty array, call trimToSize()
You can't force memory reclamation, that will happen when garbage collection occurs.
If you use clear() you will clear the references to objects that were contained in the collection. If there are no other references to those objects, then they will be reclaimed next time GC is run.
The collection itself (which just contains references, not the objects referred to), will not be resized. The only way to get back the storage used by the collection is to set the reference bars to null so it will eventually be reclaimed.
I am currently trying to diagnose a slow memory leak in my application. The facts I have so far are as follows.
I have a heap dump from a 4 day run of the application.
This heap dump contains ~800 WeakReference objects which point to objects (all of the same type, which I will call Foo for the purposes of this question) retaining 40mb of memory.
Eclipse Memory Analysis Tool shows that each of the Foo objects referred to by these WeakReferences is not referred to by any other objects. My expectation is that this should make these Foo objects Weakly Reachable and thus they should be collected at the next GC.
Each of these Foo objects has a timestamp which shows that they were allocated over the course of the 4 day run. I also have logs during this time which confirm that Garbage Collection was happening.
A huge number of Foo objects are being created by my application and only a very small fraction of them are ending up in this state within the heap dump. This suggests to me that the root cause is some sort of race condition.
My application uses JNI to call through to a native library. The JNI code calls NewGlobalRef 4 times during start of day initialisation to get references to Java classes which it uses.
What could possibly cause these Foo classes to not be collected despite only being referenced by WeakReferences (according to Eclipse Memory Analyser Tool)?
EDIT1:
#mindas
The WeakReference I am using is equivalent to the following example code.
public class FooWeakRef extends WeakReference<Foo>
{
public long longA;
public long longB;
public String stringA;
public FooWeakRef(Foo xiObject, ReferenceQueue<Foo> xiQueue)
{
super(xiObject, xiQueue);
}
}
Foo does not have a finalizer and any finalizer would not be a consideration so long as the WeakRefs have not been cleared. An object is not finalizable when it is weakly reachable. See this page for details.
#kasten The weakreferences are cleared before the object is finalizable. My heap dump shows that this has not happened.
#jarnbjo I refer to the WeakReference Javadoc:
"Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references."
This suggests to me that the GC should be detecting the fact that my Foo objects are "Weakly reachable" and "At that time" clearing the weak references.
EDIT 2
#j flemm - I know that 40mb doesn't sound like much but I am worried that 40mb in 4 days means 4000mb in 100 days. All of the docs I have read suggest that objects which are weakly reachable should not hang around for several days. I am therefore interested in any other explanations about how an object could be strongly referenced without the reference showing up in a heap dump.
I am going to try allocating some large objects when some of these dangling Foo objects are present and see whether the JVM collects them. However, this test will take a couple of days to setup and complete.
EDIT 3
#jarnbjo - I understand that I have no guarantee about when the JDK will notice that an object is weakly reachable. However, I would expect that an application under heavy load for 4 days would provide enough opportunities for the GC to notice that my objects are weakly reachable. After 4 days I am strongly suspicious that the remaining weakly references objects have been leaked somehow.
EDIT 4
#j flemm - Thats really interesting! Just to clarify, are you saying that GC is happening on your app and is not clearing Soft/Weak refs? Can you give me any more details about what JVM + GC Config you are using? My app is using a memory bar at 80% of the heap to trigger GC. I was assuming that any GC of the old gen would clear Weak refs. Are you suggesting that a GC only collects Weak refs once the memory usage is above a higher threshold? Is this higher limit configurable?
EDIT 5
#j flemm - Your comment about clearing out WeakRefs before SoftRefs is consistent with the Javadoc which states:
SoftRef: "Suppose that the garbage collector determines at a certain point in time that an object is softly reachable. At that time it may choose to clear atomically all soft references to that object and all soft references to any other softly-reachable objects from which that object is reachable through a chain of strong references. At the same time or at some later time it will enqueue those newly-cleared soft references that are registered with reference queues."
WeakRef: "Suppose that the garbage collector determines at a certain point in time that an object is weakly reachable. At that time it will atomically clear all weak references to that object and all weak references to any other weakly-reachable objects from which that object is reachable through a chain of strong and soft references. At the same time it will declare all of the formerly weakly-reachable objects to be finalizable. At the same time or at some later time it will enqueue those newly-cleared weak references that are registered with reference queues."
For clarity, are you saying that the Garbage Collector runs when your app has more than 50% free memory and in this case it does not clear WeakRefs? Why would the GC run at all when your app has >50% free memory? I think your app is probably just generating a very low amount of garbage and when the collector runs it is clearing WeakRefs but not SoftRefs.
EDIT 6
#j flemm - The other possible explanation for your app's behaviour is that the young gen is being collected but that your Weak and Soft refs are all in the old gen and are only cleared when the old gen is being collected. For my app I have stats showing that the old gen is being collected which should mean that WeakRefs get cleared.
EDIT 7
I am starting a bounty on this question. I am looking for any plausible explanations for how WeakRefs could fail to be cleared while GC is happening. If the answer is that this is impossible I would ideally like to be pointed at the appropriate bits of OpenJDK which show WeakRefs being cleared as soon as an object is determined to be weakly reachable and that weak reachability is resolved every time GC runs.
I have finally got round to checking the Hotspot JVM source code and found the following code.
In referenceProcessor.cpp:
void ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor) {
NOT_PRODUCT(verify_ok_to_handle_reflists());
assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
// Stop treating discovered references specially.
disable_discovery();
bool trace_time = PrintGCDetails && PrintReferenceGC;
// Soft references
{
TraceTime tt("SoftReference", trace_time, false, gclog_or_tty);
process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
is_alive, keep_alive, complete_gc, task_executor);
}
update_soft_ref_master_clock();
// Weak references
{
TraceTime tt("WeakReference", trace_time, false, gclog_or_tty);
process_discovered_reflist(_discoveredWeakRefs, NULL, true,
is_alive, keep_alive, complete_gc, task_executor);
}
The function process_discovered_reflist has the following signature:
void
ReferenceProcessor::process_discovered_reflist(
DiscoveredList refs_lists[],
ReferencePolicy* policy,
bool clear_referent,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor)
This shows that WeakRefs are being unconditionally cleared by ReferenceProcessor::process_discovered_references.
Searching the Hotspot code for process_discovered_reference shows that the CMS collector (which is what I am using) calls this method from the following call stack.
CMSCollector::refProcessingWork
CMSCollector::checkpointRootsFinalWork
CMSCollector::checkpointRootsFinal
This call stack looks like it is invoked every time a CMS collection is run.
Assuming this is true, the only explanation for a long lived weakly referenced object would be either a subtle JVM bug or if the GC had not been run.
You might want to check if you have leaked classloader issue. More on this topic you could find in this blog post
You need to clarify on what is the link between Foo and WeakReference. The case
class Wrapper<T> extends WeakReference<T> {
private final T referent;
public Wrapper(T referent) {
super(t);
this.referent = referent;
}
}
is very different from just
class Wrapper<T> extends WeakReferece<T> {
public Wrapper(T referent) {
super(t);
}
}
or its inlined version, WeakReference<Foo> wr = new WeakReference<Foo>(foo).
So I assume your case is not like I described in my first code snippet.
As you have said you are working with JNI, you might want to check if you have any unsafe finalizers. Every finalizer should have finally block calling super.finalize() and it's easy to slip.
You probably need to tell us more about the nature of your objects to offer better ideas.
Try SoftReference instead. Javadoc says: All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.
WeakReference doesn't have such guarantees, which makes them more suitable for caches, but sometimes SoftReferences are better.
#iirekm No: WeakReferences are 'weaker' than SoftReferences, meaning that a WeakReference will always be garbage collected before a SoftReference.
More info in this post: Understanding Java's Reference classes: SoftReference, WeakReference, and PhantomReference
Edit: (after reading comments) Yes surely Weak References are 'Weaker' than SoftReferences, typo. :S
Here's some use cases to throw further light on the subject:
SoftReference: In-memory cache (Object stays alive until VM deems that there's not enough heap mem)
WeakReference: Auto-clearing Listeners (Object should be cleared on next GC cycle after deemed being Weakly reachable)
PhantomReference: Avoiding out-of-memory errors when handling unusually large objects (When scheduled in reference queue, we know that host object is to be cleared, safe to allocate another large object). Think of it as a finalize() alternative, without the ability to bring dead objects back to life (as you potentially could with finalize)
This being said, nothing prevents the VM (please correct me if I'm wrong) to let the Weakly reachable objects stay alive as long as it is not running out of memory (as in the orig. author's case).
This is the best resource I could find on the subject: http://www.pawlan.com/monica/articles/refobjs/
Edit 2: Added "to be" in front of cleared in PhantomRef
I am not acquainted with Java, but you may be using a generational garbage collector, which will keep your Foo and FooWeakRef objects alone (not collected) as long as
they passed in an older generation
there is enough memory to allocate new objects in younger generations
Does the log that indicates that garbage collection occurred discriminates between major and minor collections?
For non-believers who claim that weak references are cleared before soft references:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
public class Test {
/**
* #param args
*/
public static void main(String[] args) {
ReferenceQueue<Object> q = new ReferenceQueue<Object>();
Map<Reference<?>, String> referenceToId = new HashMap<Reference<?>, String>();
for(int i=0; i<100; ++i) {
Object obj = new byte [10*1024*1024]; // 10M
SoftReference<Object> sr = new SoftReference<Object>(obj, q);
referenceToId.put(sr, "soft:"+i);
WeakReference<Object> wr = new WeakReference<Object>(obj, q);
referenceToId.put(wr, "weak:"+i);
for(;;){
Reference<?> ref = q.poll();
if(ref == null) {
break;
}
System.out.println("cleared reference " + referenceToId.get(ref) + ", value=" + ref.get());
}
}
}
}
If your run it with either -client or -server, you'll see that soft references are always cleared before weak references, which also agrees with Javadoc: http://download.oracle.com/javase/1.4.2/docs/api/java/lang/ref/package-summary.html#reachability
Typically soft/weak references are used in connection with Maps to make kinds of caches. If keys in your Map are compared with == operator, (or unoverriden .equals from Object), then it's best to use Map which operates on SoftReference keys (eg from Apache Commons) - when the object 'disappears' no other object will ever be equal in the '==' sense to the old one. If keys of your Map are compared with advanced .equals() operator, like String or Date, many other objects may match to the 'disappearing' one, so it's better to use the standard WeakHashMap.
Help me settle a dispute with a coworker:
Does setting a variable or collection to null in Java aid in garbage collection and reducing memory usage? If I have a long running program and each function may be iteratively called (potentially thousands of times): Does setting all the variables in it to null before returning a value to the parent function help reduce heap size/memory usage?
That's old performance lore. It was true back in 1.0 days, but the compiler and the JVM have been improved to eliminate the need (if ever there was one). This excellent IBM article gets into the details if you're interested: Java theory and practice: Garbage collection and performance
From the article:
There is one case where the use of explicit nulling is not only helpful, but virtually required, and that is where a reference to an object is scoped more broadly than it is used or considered valid by the program's specification. This includes cases such as using a static or instance field to store a reference to a temporary buffer, rather than a local variable, or using an array to store references that may remain reachable by the runtime but not by the implied semantics of the program.
Translation: "explicitly null" persistent objects that are no longer needed. (If you want. "Virtually required" too strong a statement?)
The Java VM Spec
12.6.1 Implementing Finalization
Every object can be characterized by two attributes: it may be reachable, finalizer-reachable, or unreachable, and it may also be unfinalized, finalizable, or finalized.
A reachable object is any object that can be accessed in any potential continuing computation from any live thread. Optimizing transformations of a program can be designed that reduce the number of objects that are reachable to be less than those which would naively be considered reachable. For example, a compiler or code generator may choose to set a variable or parameter that will no longer be used to null to cause the storage for such an object to be potentially reclaimable sooner.
Discussion
Another example of this occurs if the values in an object's fields are stored in registers. The program may then access the registers instead of the object, and never access the object again. This would imply that the object is garbage.
The object is reachable if it can be involved in any potential continuing computation. So if your code refers to a local variable, and nothing else refers to it, then you might cause the object to be collected by setting it to null. This would either give a null pointer exception, or change the behaviour of your program, or if it does neither you didn't need the variable in the first place.
If you are nulling out a field or an array element, then that can possibly make sense for some applications, and it will cause the memory to be reclaimed faster. Once case is creating a large array to replace an existing array referenced by a field in a class - if the field in nulled before the replacement is created, then it may relieve pressure on the memory.
Another interesting feature of Java is that scope doesn't appear in class files, so scope is not relevant to reachability; these two methods create the same bytecode, and hence the VM does not see the scope of the created object at all:
static void withBlock () {
int x = 1;
{
Object a = new Object();
}
System.out.println(x+1);
}
static void withoutBlock () {
int x = 1;
Object a = new Object();
System.out.println(x+1);
}
Not necessarily. An object becomes eligible for garbage collection when there are no live threads anymore that hold a reference to the object.
Local variables go out of scope when the method returns and it makes no sense at all to set local variables to null - the variables disappear anyway, and if there's nothing else that holds a reference the objects that the variables referred to, then those objects become eligible for garbage collection.
The key is not to look at just variables, but look at the objects that those variables refer to, and find out where those objects are referenced by your program.
It is useless on local variables, but it can be useful/needed to clear up instance variables that are not required anymore (e.g. post-initialization).
(Yeah yeah, I know how to apply the Builder pattern...)
That could only make some sense in some scenario like this:
public void myHeavyMethod() {
List hugeList = loadHugeListOfStuff(); // lots of memory used
ResultX res = processHugeList(hugeList); // compute some result or summary
// hugeList = null; // we are done with hugeList
...
// do a lot of other things that takes a LOT of time (seconds?)
// and which do not require hugeList
...
}
Here it could make some benefit to uncomment the hugeList = null line, I guess.
But it would certainly make more sense to rewrite the method (perhaps refactoring into two,
or specifying an inner scope).
Setting an object reference to null only makes it eligible for garbage collection.
It does not necessarily free up the memory,which depends on when the garbage collector runs(which depends on JVM).
When the garbage collector runs,it frees up the heap by deleting only the objects which are eligible for garbage collection.
It is a good to have. When you set objects to null, there is a possibility that the object can be garbage collected faster, in the immediate GC cycle. But there is no guaranteed mechanism to make an object garbage collected at a given time.