I am having a hard time trying to understand what is going on with Strings and memory management in Android (Java).
To simplify, have a look at this simple piece of code:
public void createArray(){
String s = "";
String foo = "foo";
String lorem = "Lorem ipsum ad his scripta blandit partiendo, eum
fastidii accumsan euripidis in, eum liber hendrerit an.";
ArrayList<Item> array = new ArrayList<Item>();
for( int i=0; i<20000; i++ ){
s = foo.replace("foo", lorem);
array.add( new Item(s) );
}
System.gc();
}
private class Item{
String name;
public Item(String name){
this.name = name;
}
}
If executed, createArray will allocate more than 5Mb in memory. Even with the System.gc() instruction, memory won't be deallocated after the loop.
Now, if we replace s = foo.replace("foo", lorem); with s = lorem;, allocated memory will only increase by 0.5Mb.
I need to understand what is going on to improve my application's performance.
Can anybody explain how should I replace Strings in a case like this? And why is System.gc() not deallocating memory?
Thanks.
UPDATE:
Thanks for the answers, now I understand that System.gc() is only a hint.
To clarify the other question (the important one):
How can I dynamically generate 20000 Strings ("foo1", "foo2"... "foo20000") add them to the ArrayList and do not run out of memory? If this 20000 strings were static they wouldn't allocate more than 0.5Mb in memory. Besides, if s = foo.replace("foo", lorem) creates a brand new String, why my function allocates 5Mb which is 10 times more memory? Shouldn't be around 1Mb?
(I am already thinking in a workaround but I want to be sure there is no way to generate the strings dynamically without using this huge amount of memory)
replace is generating a brand new String object every time it is called, since strings in Java are immutable and so modifications cannot be made "ìn-place". Also, you're adding that String to an ArrayList which will hold a reference to the new object, preventing it from being collected.
Because String's are immutable, calling foo.replace("foo", lorem) will create a new String each time. In the example where you simply set s = lorem, no new String is created.
Also, System.gc() is simply a recommendation to the VM, and it will in no way guarantee a garbage collection. There is nothing you can do to force a garbage collection. (other than using up all available memory that is)
System.gc() is a hint to the garbage collector to run again, when it has the time.
That said, the garbage collector only collects unreferenced objects, and all the strings you generated are still being held by the object array. It is entirely possible that you might add the lines after System.gc()
for (String item : array) {
System.out.println(item);
}
Which would have proven the garbage collector's wisdom in not destroying the strings.
In the event that you have some true need to reuse a String, you can trade off CPU cycles for possibly lower memory footprint with String intern methods (which will scan allocated strings for duplicates and return a reference to the single kept string if found.
You might argue that in your case the garbage collector hint could invoke compile time optimization techniques to realize that array is not being used downstream and thus act to destroy the strings before they would normally be dereferenced at the end of the program; however, it would add side effects that would appear quite strange in some runtime environments (like debugging sessions).
In the end, it is not possible to accurately perform reflection, code stepping, compile binding to source code, and various types of reflection with such exotic compile time optimization. That said, Java optimizes itself pretty well considering how many features you get out-of-the-box.
Keep in mind that System.gc() does not force the garbage collector to run. It is merely a hint that you would like it to run at some point in the future.
Related
Does assigning an unused object reference to null in Java improve the garbage collection process in any measurable way?
My experience with Java (and C#) has taught me that is often counter intuitive to try and outsmart the virtual machine or JIT compiler, but I've seen co-workers use this method and I am curious if this is a good practice to pick up or one of those voodoo programming superstitions?
Typically, no.
But like all things: it depends. The GC in Java these days is VERY good and everything should be cleaned up very shortly after it is no longer reachable. This is just after leaving a method for local variables, and when a class instance is no longer referenced for fields.
You only need to explicitly null if you know it would remain referenced otherwise. For example an array which is kept around. You may want to null the individual elements of the array when they are no longer needed.
For example, this code from ArrayList:
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
Also, explicitly nulling an object will not cause an object to be collected any sooner than if it just went out of scope naturally as long as no references remain.
Both:
void foo() {
Object o = new Object();
/// do stuff with o
}
and:
void foo() {
Object o = new Object();
/// do stuff with o
o = null;
}
Are functionally equivalent.
In my experience, more often than not, people null out references out of paranoia not out of necessity. Here is a quick guideline:
If object A references object B and you no longer need this reference and object A is not eligible for garbage collection then you should explicitly null out the field. There is no need to null out a field if the enclosing object is getting garbage collected anyway. Nulling out fields in a dispose() method is almost always useless.
There is no need to null out object references created in a method. They will get cleared automatically once the method terminates. The exception to this rule is if you're running in a very long method or some massive loop and you need to ensure that some references get cleared before the end of the method. Again, these cases are extremely rare.
I would say that the vast majority of the time you will not need to null out references. Trying to outsmart the garbage collector is useless. You will just end up with inefficient, unreadable code.
Good article is today's coding horror.
The way GC's work is by looking for objects that do not have any pointers to them, the area of their search is heap/stack and any other spaces they have. So if you set a variable to null, the actual object is now not pointed by anyone, and hence could be GC'd.
But since the GC might not run at that exact instant, you might not actually be buying yourself anything. But if your method is fairly long (in terms of execution time) it might be worth it since you will be increasing your chances of GC collecting that object.
The problem can also be complicated with code optimizations, if you never use the variable after you set it to null, it would be a safe optimization to remove the line that sets the value to null (one less instruction to execute). So you might not actually be getting any improvement.
So in summary, yes it can help, but it will not be deterministic.
At least in java, it's not voodoo programming at all. When you create an object in java using something like
Foo bar = new Foo();
you do two things: first, you create a reference to an object, and second, you create the Foo object itself. So long as that reference or another exists, the specific object can't be gc'd. however, when you assign null to that reference...
bar = null ;
and assuming nothing else has a reference to the object, it's freed and available for gc the next time the garbage collector passes by.
It depends.
Generally speaking shorter you keep references to your objects, faster they'll get collected.
If your method takes say 2 seconds to execute and you don't need an object anymore after one second of method execution, it makes sense to clear any references to it. If GC sees that after one second, your object is still referenced, next time it might check it in a minute or so.
Anyway, setting all references to null by default is to me premature optimization and nobody should do it unless in specific rare cases where it measurably decreases memory consuption.
Explicitly setting a reference to null instead of just letting the variable go out of scope, does not help the garbage collector, unless the object held is very large, where setting it to null as soon as you are done with is a good idea.
Generally setting references to null, mean to the READER of the code that this object is completely done with and should not be concerned about any more.
A similar effect can be achieved by introducing a narrower scope by putting in an extra set of braces
{
int l;
{ // <- here
String bigThing = ....;
l = bigThing.length();
} // <- and here
}
this allows the bigThing to be garbage collected right after leaving the nested braces.
public class JavaMemory {
private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
public void f() {
{
byte[] data = new byte[dataSize];
//data = null;
}
byte[] data2 = new byte[dataSize];
}
public static void main(String[] args) {
JavaMemory jmp = new JavaMemory();
jmp.f();
}
}
Above program throws OutOfMemoryError. If you uncomment data = null;, the OutOfMemoryError is solved. It is always good practice to set the unused variable to null
I was working on a video conferencing application one time and noticed a huge huge huge difference in performance when I took the time to null references as soon as I didn't need the object anymore. This was in 2003-2004 and I can only imagine the GC has gotten even smarter since. In my case I had hundreds of objects coming and going out of scope every second, so I noticed the GC when it kicked in periodically. However after I made it a point to null objects the GC stopped pausing my application.
So it depends on what your doing...
Yes.
From "The Pragmatic Programmer" p.292:
By setting a reference to NULL you reduce the number of pointers to the object by one ... (which will allow the garbage collector to remove it)
I assume the OP is referring to things like this:
private void Blah()
{
MyObj a;
MyObj b;
try {
a = new MyObj();
b = new MyObj;
// do real work
} finally {
a = null;
b = null;
}
}
In this case, wouldn't the VM mark them for GC as soon as they leave scope anyway?
Or, from another perspective, would explicitly setting the items to null cause them to get GC'd before they would if they just went out of scope? If so, the VM may spend time GC'ing the object when the memory isn't needed anyway, which would actually cause worse performance CPU usage wise because it would be GC'ing more earlier.
Even if nullifying the reference were marginally more efficient, would it be worth the ugliness of having to pepper your code with these ugly nullifications? They would only be clutter and obscure the intent code that contains them.
Its a rare codebase that has no better candidate for optimisation than trying to outsmart the Garbage collector (rarer still are developers who succeed in outsmarting it). Your efforts will most likely be better spent elsewhere instead, ditching that crufty Xml parser or finding some opportunity to cache computation. These optimisations will be easier to quantify and don't require you dirty up your codebase with noise.
Oracle doc point out "Assign null to Variables That Are No Longer Needed" https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
"It depends"
I do not know about Java but in .net (C#, VB.net...) it is usually not required to assign a null when you no longer require a object.
However note that it is "usually not required".
By analyzing your code the .net compiler makes a good valuation of the life time of the variable...to accurately tell when the object is not being used anymore. So if you write obj=null it might actually look as if the obj is still being used...in this case it is counter productive to assign a null.
There are a few cases where it might actually help to assign a null. One example is you have a huge code that runs for long time or a method that is running in a different thread, or some loop. In such cases it might help to assign null so that it is easy for the GC to know its not being used anymore.
There is no hard & fast rule for this. Going by the above place null-assigns in your code and do run a profiler to see if it helps in any way. Most probably you might not see a benefit.
If it is .net code you are trying to optimize, then my experience has been that taking good care with Dispose and Finalize methods is actually more beneficial than bothering about nulls.
Some references on the topic:
http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx
http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx
In the future execution of your program, the values of some data members will be used to computer an output visible external to the program. Others might or might not be used, depending on future (And impossible to predict) inputs to the program. Other data members might be guaranteed not to be used. All resources, including memory, allocated to those unused data are wasted. The job of the garbage collector (GC) is to eliminate that wasted memory. It would be disastrous for the GC to eliminate something that was needed, so the algorithm used might be conservative, retaining more than the strict minimum. It might use heuristic optimizations to improve its speed, at the cost of retaining some items that are not actually needed. There are many potential algorithms the GC might use. Therefore it is possible that changes you make to your program, and which do not affect the correctness of your program, might nevertheless affect the operation of the GC, either making it run faster to do the same job, or to sooner identify unused items. So this kind of change, setting an unusdd object reference to null, in theory is not always voodoo.
Is it voodoo? There are reportedly parts of the Java library code that do this. The writers of that code are much better than average programmers and either know, or cooperate with, programmers who know details of the garbage collector implementations. So that suggests there is sometimes a benefit.
As you said there are optimizations, i.e. JVM knows the place when the variable was last used and the object referenced by it can be GCed right after this last point (still executing in current scope). So nulling out references in most cases does not help GC.
But it can be useful to avoid "nepotism" (or "floating garbage") problem (read more here or watch video). The problem exists because heap is split into Old and Young generations and there are different GC mechanisms applied: Minor GC (which is fast and happens often to clean young gen) and Major Gc (which causes longer pause to clean Old gen). "Nepotism" does not allow for garbage in Young gen to be collected if it is referenced by garbage which was already tenured to an Old gen.
This is 'pathological' because ANY promoted node will result in the promotion of ALL following nodes until a GC resolves the issue.
To avoid nepotism it's a good idea to null out references from an object which is supposed to be removed. You can see this technique applied in JDK classes: LinkedList and LinkedHashMap
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
// ...
}
This question already has answers here:
Is the garbage collector guaranteed to run before Out of Memory Error?
(5 answers)
Closed 9 years ago.
This is a theoretical question. I am just curios that if Java has a mechanism for garbage collection to free the memory, then why does still OutOfMemoryError occur?
I searched SO for this but could get these links
Is the garbage collector guaranteed to run before Out of Memory Error?
Garbage collection before OutOfMemoryError
These do not answer my question specifically. If Java allows memory so well by using garbage collection, then why does OutOfMemoryError occur?
An OutOfMemoryError can occur if none of the objects in memory is eligible for garbage collection. For example:
List<MyClass> hellos = new ArrayList<>();
for (;;) {
hellos.add(new MyClass());
}
This creates a list and keeps adding MyClass objects to it until memory runs out. None of the objects is eligible for garbage collection because there are references to all of them.
It is also possible to sequester memory in ways you don't expect. Consider the following string example.
char[] chars = new char[10_000_000]; // May need to adjust.
String string = new String(chars);
chars = null;
String substring = string.substring(5_000_000);
string = null;
The chars array may be collected. The array inside string may not be collected, because substring contains a reference to the internal array followed by an offset and range into it. So, 107 characters remain allocated, even though only 5 * 106 are used and accessible.
Java 1.7.0_06
It seems that String.substring no longer has this behavior. In an article in the Java Performance Tuning Guide web site, Mikhail Vorontsov reports that in Java 1.7.0_06 and higher, String.substring always creates a new String independent of the old one. The String class no longer has offset and range instance variables. Creating a large string, taking substrings, and throwing away the original will not leave the old string's char[] sequestered.
// Java 1.7.0_06 and up
char[] chars = new char[10_000_000]; // May need to adjust.
String string = new String(chars);
chars = null;
String substring = string.substring(5_000_000);
// Copies a portion of string's array to a new array.
string = null;
// string's array is no longer reachable, and may be garbage collected.
Because not all memory is garbage.
Garbage collector works on memory that is not going to be used.
However, if you allocate memory, and that memory is in scope, that means, garbage collector can't really clean that memory.
When the memory allocated is too high above the allowed for the VM, you get that exception.
An object that's still has a reference to it from running code can't be collected. So if there's a way to even theoretically access an object, it's stuck in memory.
Just so it's said, Java doesn't eliminate the need to care about memory; it just automates a whole lot of the memory management stuff. You still have to do your part to ensure that you aren't squirreling away objects after their useful life is over...cause as long as they can be reached (however indirectly), they are taking up memory that can't be reclaimed.
It is better to nullify your objects once your work has been completed with them, so you make sure the objects to be available to the garbage collector in order to avoid the problems regarding out of memory or memory leak.
If you run out of memory and there is no variable or object eligible for removing, the except will be raised.
So best way to use GC(Garbage collection) is:
Explicitly assign the variable to null value if it is no used any more.
I am working on improving the performance of my app. I am confused about which of the following will use more memory: Here sb is StringBuffer
String strWithLink = sb.toString();
clickHereTextview.setText(
Html.fromHtml(strWithLink.substring(0,strWithLink.indexOf("+"))));
OR
clickHereTextview.setText(
Html.fromHtml(sb.toString().substring(0,sb.toString().indexOf("+"))));
In terms of memory an expression such as
sb.toString().indexOf("+")
has little to no impact as the string will be garbage collected right after evaluation. (To avoid even the temporary memory usage, I would recommend doing
sb.indexOf("+")
instead though.)
However, there's a potential leak involved when you use String.substring. Last time I checked the the substring basically returns a view of the original string, so the original string is still resident in memory.
The workaround is to do
String strWithLink = sb.toString();
... new String(strWithLink.substring(0,strWithLink.indexOf("+"))) ...
^^^^^^^^^^
to detach the wanted string, from the original (potentially large) string. Same applies for String.split as discussed over here:
Java String.split memory leak?
The second will use more memory, because each call to StringBuilder#toString() creates a new String instance.
http://www.docjar.com/html/api/java/lang/StringBuilder.java.html
Analysis
If we look at StringBuilder's OpenJDK sources:
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
We see, that it instantiates a whole new String object. It places in the string pool as many new instances as many times you call sb.toString().
Outcome
Use String strWithLink = sb.toString();, reusing it will retrieve the same instance of String from the pool, rather the new one.
Check other people's answers, the second one does take a little bit more memory, but this sounds like you are over optimizing. Keeping your code clear and readable should be the priority. I'd suggest you don't worry so much about such tiny optimizations if readability will suffer.
The less work you do, the more efficient it usually is. In this case, you don't need to call toString at all
clickHereTextview.setText(Html.fromHtml(sb.substring(0, sb.indexOf("+"))));
Creating new objects always take up more memory. However, in your case difference seems insignificant.
Also, in your case, you are creating a local variable which takes heap space.
Whenever there are references in more than one location in your method it good to use
String strWithLink = sb.toString();, as you can use the same strWithLink everywhere . Otherwise, if there is only one reference, its always better to just use sb.toString(); directly.
I ran those code and I got some questions, this kinda got weird.
Using String:
while(true)
{
String s = String.valueOf(System.currentTimeMillis());
System.out.println(s);
Thread.sleep(10);
}
Using StringBuilder:
StringBuilder s = null;
while(true)
{
s = new StringBuilder();
s.append(System.currentTimeInMillis());
System.out.println(s);
Thread.sleep(10);
}
In both cases they get stuck in 12540 K waste of memory. Running this test on Windows XP SP2.
Why are they wasting the same amount of memory?
Why did immutable String stop wasting memory?
Off-topic: How can I convert StringBuilder to byte array encoded in a specific charset?
It is hard to figure out what you are actually asking here, but the application is behaving exactly as I would expect.
Strings are immutable and the garbage collector doesn't take them out. isn't it
Both mutable and immutable objects may be garbage collected in Java.
The actual criterion that determines whether an object is actually garbage collected is it reachability. In simple terms, when the garbage collector figures out that the application can no longer use an object, the object will be deleted.
In both of your applications, objects of roughly the same size are being created once every 10 milliseconds. In each iteration, a new object is being created and its reference is being assigned to s, replacing the previous reference. This makes the previous object unreachable, and eligible for garbage collection. At some point, the Java VM decides to run the garbage collector. This gets rid of all of the unreachable object ... and the application continues.
I read that common Strings are not collected ever by the garbage collector, is that false?
This is false on two counts:
Strings created by new String(...), String.substring(...)1 and so on are no different from any other Java object.
Strings that are interned (by calling String.intern()) are stored in the string pool which is held in the PermGen heap2. However, even the PermGen heap is garbage collected, albeit on longer timescales that the heap in which objects are normally created.
(Once upon a time, the PermGen heap was not garbage collected, but that was changed a long time ago.)
As #MichaelBorgwardt correctly identified, you were confusing string objects (in general) with string objects that correspond to string literals. The latter are interned automatically, and end up in the string pool. However, they may still be subject to garbage collection. This can happen if the parent class is unloaded and nothing else references the literal.
1 - In Java 6 and earlier, there is a difference between strings created using new String and using String.substring. In the latter case, the original string and the substring would share the backing array that holds the string's characters. In Java 7, this changed. String.substring now creates a new backing array.
2 - From Java 7 onwards, the string pool is just a (hidden) data structure in the normal heap. From Java 8 onwards, the PermGen heap no longer exists.
You are confusing two very different things:
Strings are immutable, but this has nothing to do with whether or not they are garbage collected. However, it means that if you need to make a lot of changes to a String (such as building a big string by appending one character at a time), then you end up making lots of copies and a lot of work for the garbage collector.
String literals (i.e. Strings that are written directly in the source code) are part of a pool of interned Strings and generally not garbage collected. However, this is done in order to allow multiple instances of the same String in the source code to be replaced by references to the same object, which can save a lot of space. And this is only possible because Strings are immutable, so two parts of the program holding a reference to the same String cannot interfere with each other.
You seem to assume that a mutable class would waste more memory than a non-mutable class. I don't understand why.
Your code is wrong, if it's intended to allocate more memory in each loop. It just assigns the s reference to a new object, hence the previous one is lost and will be garbage collected eventually.
To look at the OS memory for the JVM is a very rough/imprecise estimation of the Java allocated memory.
StringBuilder and String (and StringBuffer and char[] ) are all efficient, they allocate approximately 2 bytes per char (Java uses some UTF-16 variation) plus a small (negligible for big strings) overhead.
Because you are building and throwing. In fact, you are not really building any string using StringBuilder. Notice, you are instantiating a new StringBuilder object in every go.
As already explained, since you are not mutating the string but rather just pointing s to a new value; the old value has to be garbage collected. Here is a snippet using stringBuffer to try to actually mutate the value s is pointing to.
StringBuffer s = new StringBuffer();
while(true)
{
s.replace(0,13,Long.toString(System.currentTimeMillis()));
System.out.println(s);
Thread.sleep(10);
}
It should be noted that this doesn't solve the problem because of two things. First of all we have to make a new String everytime using Long.toString(), and secondly since s.toString() will be called; this will make a new String sharing the value of stringBuffer (atleast this was the case last time I checked). When we do s.replace it will allocate a new array to hold this new string in order to preserve the unmutability of the String.
Actually, In this trivial case, the best you can do (as far as I know) is:
while(true)
{
System.out.println(Long.toString(System.currentTimeMillis()));
Thread.sleep(10);
}
Wanted to post this as a reply to Stephen C, but for some reason I can't; so here is a point of clarification...
String.subString(...) does NOT create a new String. It references a point within an existing String, and returning substring values is one sure way to introduce memory leaks into your app (especially if building a list of Strings based on substring values of another list of strings).
Best practice in this case is:
return new String(s.subString(...));
Does assigning an unused object reference to null in Java improve the garbage collection process in any measurable way?
My experience with Java (and C#) has taught me that is often counter intuitive to try and outsmart the virtual machine or JIT compiler, but I've seen co-workers use this method and I am curious if this is a good practice to pick up or one of those voodoo programming superstitions?
Typically, no.
But like all things: it depends. The GC in Java these days is VERY good and everything should be cleaned up very shortly after it is no longer reachable. This is just after leaving a method for local variables, and when a class instance is no longer referenced for fields.
You only need to explicitly null if you know it would remain referenced otherwise. For example an array which is kept around. You may want to null the individual elements of the array when they are no longer needed.
For example, this code from ArrayList:
public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
Also, explicitly nulling an object will not cause an object to be collected any sooner than if it just went out of scope naturally as long as no references remain.
Both:
void foo() {
Object o = new Object();
/// do stuff with o
}
and:
void foo() {
Object o = new Object();
/// do stuff with o
o = null;
}
Are functionally equivalent.
In my experience, more often than not, people null out references out of paranoia not out of necessity. Here is a quick guideline:
If object A references object B and you no longer need this reference and object A is not eligible for garbage collection then you should explicitly null out the field. There is no need to null out a field if the enclosing object is getting garbage collected anyway. Nulling out fields in a dispose() method is almost always useless.
There is no need to null out object references created in a method. They will get cleared automatically once the method terminates. The exception to this rule is if you're running in a very long method or some massive loop and you need to ensure that some references get cleared before the end of the method. Again, these cases are extremely rare.
I would say that the vast majority of the time you will not need to null out references. Trying to outsmart the garbage collector is useless. You will just end up with inefficient, unreadable code.
Good article is today's coding horror.
The way GC's work is by looking for objects that do not have any pointers to them, the area of their search is heap/stack and any other spaces they have. So if you set a variable to null, the actual object is now not pointed by anyone, and hence could be GC'd.
But since the GC might not run at that exact instant, you might not actually be buying yourself anything. But if your method is fairly long (in terms of execution time) it might be worth it since you will be increasing your chances of GC collecting that object.
The problem can also be complicated with code optimizations, if you never use the variable after you set it to null, it would be a safe optimization to remove the line that sets the value to null (one less instruction to execute). So you might not actually be getting any improvement.
So in summary, yes it can help, but it will not be deterministic.
At least in java, it's not voodoo programming at all. When you create an object in java using something like
Foo bar = new Foo();
you do two things: first, you create a reference to an object, and second, you create the Foo object itself. So long as that reference or another exists, the specific object can't be gc'd. however, when you assign null to that reference...
bar = null ;
and assuming nothing else has a reference to the object, it's freed and available for gc the next time the garbage collector passes by.
It depends.
Generally speaking shorter you keep references to your objects, faster they'll get collected.
If your method takes say 2 seconds to execute and you don't need an object anymore after one second of method execution, it makes sense to clear any references to it. If GC sees that after one second, your object is still referenced, next time it might check it in a minute or so.
Anyway, setting all references to null by default is to me premature optimization and nobody should do it unless in specific rare cases where it measurably decreases memory consuption.
Explicitly setting a reference to null instead of just letting the variable go out of scope, does not help the garbage collector, unless the object held is very large, where setting it to null as soon as you are done with is a good idea.
Generally setting references to null, mean to the READER of the code that this object is completely done with and should not be concerned about any more.
A similar effect can be achieved by introducing a narrower scope by putting in an extra set of braces
{
int l;
{ // <- here
String bigThing = ....;
l = bigThing.length();
} // <- and here
}
this allows the bigThing to be garbage collected right after leaving the nested braces.
public class JavaMemory {
private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);
public void f() {
{
byte[] data = new byte[dataSize];
//data = null;
}
byte[] data2 = new byte[dataSize];
}
public static void main(String[] args) {
JavaMemory jmp = new JavaMemory();
jmp.f();
}
}
Above program throws OutOfMemoryError. If you uncomment data = null;, the OutOfMemoryError is solved. It is always good practice to set the unused variable to null
I was working on a video conferencing application one time and noticed a huge huge huge difference in performance when I took the time to null references as soon as I didn't need the object anymore. This was in 2003-2004 and I can only imagine the GC has gotten even smarter since. In my case I had hundreds of objects coming and going out of scope every second, so I noticed the GC when it kicked in periodically. However after I made it a point to null objects the GC stopped pausing my application.
So it depends on what your doing...
Yes.
From "The Pragmatic Programmer" p.292:
By setting a reference to NULL you reduce the number of pointers to the object by one ... (which will allow the garbage collector to remove it)
I assume the OP is referring to things like this:
private void Blah()
{
MyObj a;
MyObj b;
try {
a = new MyObj();
b = new MyObj;
// do real work
} finally {
a = null;
b = null;
}
}
In this case, wouldn't the VM mark them for GC as soon as they leave scope anyway?
Or, from another perspective, would explicitly setting the items to null cause them to get GC'd before they would if they just went out of scope? If so, the VM may spend time GC'ing the object when the memory isn't needed anyway, which would actually cause worse performance CPU usage wise because it would be GC'ing more earlier.
Even if nullifying the reference were marginally more efficient, would it be worth the ugliness of having to pepper your code with these ugly nullifications? They would only be clutter and obscure the intent code that contains them.
Its a rare codebase that has no better candidate for optimisation than trying to outsmart the Garbage collector (rarer still are developers who succeed in outsmarting it). Your efforts will most likely be better spent elsewhere instead, ditching that crufty Xml parser or finding some opportunity to cache computation. These optimisations will be easier to quantify and don't require you dirty up your codebase with noise.
Oracle doc point out "Assign null to Variables That Are No Longer Needed" https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
"It depends"
I do not know about Java but in .net (C#, VB.net...) it is usually not required to assign a null when you no longer require a object.
However note that it is "usually not required".
By analyzing your code the .net compiler makes a good valuation of the life time of the variable...to accurately tell when the object is not being used anymore. So if you write obj=null it might actually look as if the obj is still being used...in this case it is counter productive to assign a null.
There are a few cases where it might actually help to assign a null. One example is you have a huge code that runs for long time or a method that is running in a different thread, or some loop. In such cases it might help to assign null so that it is easy for the GC to know its not being used anymore.
There is no hard & fast rule for this. Going by the above place null-assigns in your code and do run a profiler to see if it helps in any way. Most probably you might not see a benefit.
If it is .net code you are trying to optimize, then my experience has been that taking good care with Dispose and Finalize methods is actually more beneficial than bothering about nulls.
Some references on the topic:
http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx
http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx
In the future execution of your program, the values of some data members will be used to computer an output visible external to the program. Others might or might not be used, depending on future (And impossible to predict) inputs to the program. Other data members might be guaranteed not to be used. All resources, including memory, allocated to those unused data are wasted. The job of the garbage collector (GC) is to eliminate that wasted memory. It would be disastrous for the GC to eliminate something that was needed, so the algorithm used might be conservative, retaining more than the strict minimum. It might use heuristic optimizations to improve its speed, at the cost of retaining some items that are not actually needed. There are many potential algorithms the GC might use. Therefore it is possible that changes you make to your program, and which do not affect the correctness of your program, might nevertheless affect the operation of the GC, either making it run faster to do the same job, or to sooner identify unused items. So this kind of change, setting an unusdd object reference to null, in theory is not always voodoo.
Is it voodoo? There are reportedly parts of the Java library code that do this. The writers of that code are much better than average programmers and either know, or cooperate with, programmers who know details of the garbage collector implementations. So that suggests there is sometimes a benefit.
As you said there are optimizations, i.e. JVM knows the place when the variable was last used and the object referenced by it can be GCed right after this last point (still executing in current scope). So nulling out references in most cases does not help GC.
But it can be useful to avoid "nepotism" (or "floating garbage") problem (read more here or watch video). The problem exists because heap is split into Old and Young generations and there are different GC mechanisms applied: Minor GC (which is fast and happens often to clean young gen) and Major Gc (which causes longer pause to clean Old gen). "Nepotism" does not allow for garbage in Young gen to be collected if it is referenced by garbage which was already tenured to an Old gen.
This is 'pathological' because ANY promoted node will result in the promotion of ALL following nodes until a GC resolves the issue.
To avoid nepotism it's a good idea to null out references from an object which is supposed to be removed. You can see this technique applied in JDK classes: LinkedList and LinkedHashMap
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
// ...
}