how does garbage collection with respect to Strings in Java? - java

I am reading about memory management in JVM and that if an object has no more references to it, it is garbage collected.
lets say, I have a program
public test {
public static void main(String[ ] args) {
String name = "hello";
for (int i =0 ; i < 5; i++) {
System.out.println(i);
}
}
}
As you can see, the String name is not used anywhere, so its reference is kept through out and not garbage collected.
now I have,
String name = "hello"
String name2 = name.substring(1,4)//"ell"
here again, the reference for hello must be present always, and cannot be garbage collected, since name2 uses it.
so when do these String or any objects get garbage collected, which have references but are obsolete, i.e. no longer used in code?
I can see one scenario where trimming down an array causes memory leak and hence setting its reference to null is a good way to garbage collect those obsolete references.

I can see one scenario where trimming down an array causes memory leak
and hence setting its reference to null is a good way to garbage
collect those obsolete references.
Strings are reference types, so all the rules for reference types with respect to garbage collection apply to strings. The JVM may also do some optimizations on String literals but if you're worrying about these, then you're probably thinking too hard.
When does the JVM collect unreferenced objects?
The only answer that matters is: you can't tell and it needn't ever, but if it does you can't know when that will be. You should never write Java code around deterministic garbage collection. It is unnecessary and fraught with ugliness.
Speaking generally, if you confine your reference variables (including arrays or collections of reference types) to the narrowest possible scope, then you'll already have gone a long way toward not having to worry about memory leaks. Long-lived reference types will require some care and feeding.
"Trimming" arrays (unreferencing array elements by assigning null to them) is ONLY necessary in the special case where the array represents your own system for managing memory, eg. if you are making your own cache or queue of objects.
Because the JVM can't know that your array is "managing memory" it can't collect unused objects in it that are still referenced but are expired. In cases where an array represents your own system for managing memory, then you should assign null to array elements whose objects have expired (eg. popped off a queue; J. Bloch, Essential Java, 2nd Ed.).

Technically, the JVM is not required to garbage-collect objects ever. In practice, they usually come behind a little while after the last reference is gone and free up the memory.
First, be aware that constants are always going to be around. Even if you assign a new value to name, the system still has a copy of "hello" stored with the class that it will reuse every time you hit that initializer statement.
However, don't confuse using an object for some sort of calculation with keeping a reference to it forever. In your second example, while "hello" is in fact kept around, that's just because it's living in the constant pool; name2 doesn't have any sort of "hold" on it that keeps it in memory. The call to substring executes and finishes, and there's no eternal hold on name. (The actual implementation in the Oracle JVM shares the underlying char[], but that's implementation-dependent.)
Clearing out arrays is a good practice because it's common for them to be long-lived and reused. If the entire array gets garbage collected, the references it holds get erased (and their objects garbage collected if those were the last ones).

Every variable in Java has a scope: The piece of code during which the variable is defined. The scope of a local variable like name in your example is between the brackets {} it is in. Thus, the name variable will be defined when the thread reaches the String name = "hello"; declaration, and will be kept alive until the main method is finished (because then the brackets the variable was in are closed).
Strings are a different story though than other variables. Strings are cached internally and may not actually be made available for the garbage collector yet.

Related

How Java manages variables in memory

Let's say I have this code:
{
int var = 2;
// more code
}
What happens with 'var' after the code is executed and it is not used anymore? Is it deleted from memory or it stays there occupying memory, or something else?
Related to this, is it better to work with variables that way^, or to make some global variable and just change it's value?
Local variables live on the stack. If it's a reference to an object then only variable is on the stack.
Instance variables live on the heap because they belong to an object.
Also this post (Stack and heap memory in java) might be helpful.
To make a long story short, in java (and other JVM languages), you don't have to care about memory allocation and dealocation at all. You really shouldn't be worrying about it. Once you lose the reference to that variable (in this case, when the method call ends), the variable is effectively gone. Some indefinite amount of time after that, the Garbage collecting thread will notice that you can't possibly access that variable anymore, and free up the memory it was using.
See: Garbage Collection in Java.
if you are defining any variable as instance variable then that variable will be used by instance. and instance will be saved in Heap memory area.
Garbage collector will run periodically to clean non referenced object from memory.
but if that variable is defined inside any block or method then that will be stored Stack memory.
Java Stack memory is used for execution of a thread. They contain method specific values that are short-lived and references to other objects in the heap that are getting referred from the method. Stack memory is always referenced in LIFO (Last-In-First-Out) order. Whenever a method is invoked, a new block is created in the stack memory for the method to hold local primitive values and reference to other objects in the method. As soon as method ends, the block becomes unused and become available for next method.
Everything in Java is removed from memory when it is no longer referenced. It takes a lot of effort to cause true memory leaks in Java.
Java primitives like int, boolean, and char are put on the stack and removed from memory as soon as they leave scope. Java objects like String, arrays, or ArrayList are allocated on the heap (and referenced by the local variable on the stack). Objects are garbage collected (removed from memory) when there is no longer a reference to them.Static variables belong to a class and will be a reference an object as long as the class is loaded, which is usually the entire run time of the Java program. Statics are the closest thing Java has to global variables, but overuse or misuse of statics is actually a way to cause memory issues rather than solve them.

Will a substring of another string prevent the parent string from being garbage collected?

String samplel = "ToBeGarbageCollected";
String sample2 = samplel.substring(0, 1);
samplel = null;
I know substring internally will keep a reference for original String.
But by explicitly defining samplel as null, will sample1 and sample2 be available for garbage Collection?
I remember seeing somewhere if a parent object is explicitly set to null all child values are available for garbage collection. Will this hold good for the above?
I am just curious if this the parent child relationship scenario? If not, will this cause sample1 or sample2 to be available for garbage collection?
String samplel = "ToBeGarbageCollected";
String sample2 = new String(samplel .substring(0, 1));
samplel = null;
First thing to say is that garbage collection doesn't happen immediately. So assigning null to anything does not / cannot cause garbage collection. What is may do is to cause an object to become unreachable ... and that will make it a potential candidate for garbage collection in a future GC run.
Now to your specific examples.
Important Note: the following only applies to older JVMs; i.e. Java 7 update 5 and earlier. In Java 7 update 6, they changed String.substring() so that the target string and resulting substring DO NOT share the backing array. This eliminates the potential storage leak issue with substring.
The substring method doesn't put a reference to the original String in the new String. What it actually does is save a reference to the original String's backing array; i.e the array that holds the characters.
But having said that, assigning null to samplel is not sufficient to make the state of the entire original string unreachable. The original String's entire backing array will be remain reachable ... and that means it won't be a candidate for garbage collection.
But there is another complication. You set sample1 to a String literal, and the String object that represents a String literal is always reachable (unless the entire class gets unloaded!)
But by explicitly defining samplel as null, will sample1 and sample2 be available for garbage Collection?
The original sample1 object will remain fully reachable, and sample2 will remain be reachable unless that variable goes out of scope.
If sample1 had not been a literal and there were no other references to it, then the answer would be different. The sample1 object would be unreachable, but its backing array would still be reachable via sample2.
In your second example, copying the substring causes a new String to be created. And it is guaranteed that the new String won't share the backing array with the original String and the temporary substring. In that case, assigning null is unnecessary.
Will now both sample1 and sample2 be available for garbage Collection?
The answer is the same as for the above for the case where sample1 is a literal.
If sample1 is not a literal and there are no other references to it, then sample1 and the temporary substring would now be unreachable.
I just want to know where does String constructor be helpful.
In theory it will be.
In practice it depends on whether the references are still reachable when the GC eventually gets around to looking ... and also on whether the Strings in question are large enough and numerous enough to have a significant impact on memory usage.
And in practice, that precondition is usually NOT satisfied and creating a fresh String like that usually does NOT help.
Remember that in Java String is immutable. In this case, sample1 will be discarded, but sample2 never pointed to sample1: it pointed to a separately held immutable string in the JVM that was created at the latest when substring was called.
When you set sample1 to null, the memory it pointed to became available for garbage collection (assuming no other strings held the same value and no other variables were pointed at that location). When you use the new keyword (or implicitly do so through the assignment of a primitive) new memory is allocated on the heap (usually; again, strings are immutable and share the same memory). If no pointers (read: any named variables) point to a given location of memory, it is available for garbage collection.
Remember: in any case where there are no references to an object, it becomes available for garbage collection. Objects are not defined by the variable names assigned to them, but rather are locations in memory, and the variable names act as pointers (references) to those objects. Strings are somewhat different because they are immutable, and the JVM may opt not to garbage collect for reasons independent of references to them.

regarding garbage collection and references

I have a question regarding references and garbage collector in java.
When calling a method with a parameter, let say an array, it is sent a copy of the reference of the array that is considered the parameter.
Hypothesis: the garbage collector is triggered exactly after calling the method, or when executing operations inside the method to the considered array.
Is now the same reference for the array in the calling method and in the called method, regardless of the operations and moves done by the garbage collector (the garbage collector can move the reference from eden to survivor 1)?
A simpler expression for the question: can you rely on this reference copy in order to use it as a mechanism for parameters sent 'by reference'?
Thank you very much!
Roxana
If you're trying to ask whether you can fake pass by reference like this:
// We'd like to pass x by reference...
String x = "hello";
String[] array = { x };
foo(array);
x = array[0];
...
static void foo(String[] array)
{
array[0] = array[0] + "foo";
}
... then yes, that will always work, and isn't affected by garbage collection.
I'd personally try to avoid it, but yes, it'll work :)
Note that unlike with real pass-by-reference, if the method throws an exception then the assignment after the method call won't occur, so you'll lose the "change".
Garbage collector removes object that cannot be accessed by any reference. In your example there are at least 2 references that can be used to access object. Therefore it will not be removed and you can be use references to access it.
Some garbage collectors work by finding objects with no references and reclaiming the space they occupy.
Others work by finding all objects with references, and moving them to a new object space. When all objects have been moved, the old object space is reclaimed. In that case, all the references are updated.

If Java Strings are immutable and StringBuilder is mutable why they wasting same amount of memory in my code?

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 setting Java objects to null do anything anymore?

I was browsing some old books and found a copy of "Practical Java" by Peter Hagger. In the performance section, there is a recommendation to set object references to null when no longer needed.
In Java, does setting object references to null improve performance or garbage collection efficiency? If so, in what cases is this an issue? Container classes? Object composition? Anonymous inner classes?
I see this in code pretty often. Is this now obsolete programming advice or is it still useful?
It depends a bit on when you were thinking of nulling the reference.
If you have an object chain A->B->C, then once A is not reachable, A, B and C will all be eligible for garbage collection (assuming nothing else is referring to either B or C). There's no need, and never has been any need, to explicitly set references A->B or B->C to null, for example.
Apart from that, most of the time the issue doesn't really arise, because in reality you're dealing with objects in collections. You should generally always be thinking of removing objects from lists, maps etc by calling the appropiate remove() method.
The case where there used to be some advice to set references to null was specifically in a long scope where a memory-intensive object ceased to be used partway through the scope. For example:
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; <-- explicitly set to null
doSomethingElse();
}
The rationale here was that because obj is still in scope, then without the explicit nulling of the reference, it does not become garbage collectable until after the doSomethingElse() method completes. And this is the advice that probably no longer holds on modern JVMs: it turns out that the JIT compiler can work out at what point a given local object reference is no longer used.
No, it's not obsolete advice. Dangling references are still a problem, especially if you're, say, implementing an expandable array container (ArrayList or the like) using a pre-allocated array. Elements beyond the "logical" size of the list should be nulled out, or else they won't be freed.
See Effective Java 2nd ed, Item 6: Eliminate Obsolete Object References.
Instance fields, array elements
If there is a reference to an object, it cannot be garbage collected. Especially if that object (and the whole graph behind it) is big, there is only one reference that is stopping garbage collection, and that reference is not really needed anymore, that is an unfortunate situation.
Pathological cases are the object that retains an unnessary instance to the whole XML DOM tree that was used to configure it, the MBean that was not unregistered, or the single reference to an object from an undeployed web application that prevents a whole classloader from being unloaded.
So unless you are sure that the object that holds the reference itself will be garbage collected anyway (or even then), you should null out everything that you no longer need.
Scoped variables:
If you are considering setting a local variable to null before the end of its scope , so that it can be reclaimed by the garbage collector and to mark it as "unusable from now on", you should consider putting it in a more limited scope instead.
{
BigObject obj = ...
doSomethingWith(obj);
obj = null; // <-- explicitly set to null
doSomethingElse();
}
becomes
{
{
BigObject obj = ...
doSomethingWith(obj);
} // <-- obj goes out of scope
doSomethingElse();
}
Long, flat scopes are generally bad for legibility of the code, too. Introducing private methods to break things up just for that purpose is not unheard of, too.
In memory restrictive environments (e.g. cellphones) this can be useful. By setting null, the objetc don't need to wait the variable to get out of scope to be gc'd.
For the everyday programming, however, this shouldn't be the rule, except in special cases like the one Chris Jester-Young cited.
Firstly, It does not mean anything that you are setting a object to null. I explain it below:
List list1 = new ArrayList();
List list2 = list1;
In above code segment we are creating the object reference variable name list1 of ArrayList object that is stored in the memory. So list1 is referring that object and it nothing more than a variable. And in the second line of code we are copying the reference of list1 to list2. So now going back to your question if I do:
list1 = null;
that means list1 is no longer referring any object that is stored in the memory so list2 will also having nothing to refer. So if you check the size of list2:
list2.size(); //it gives you 0
So here the concept of garbage collector arrives which says «you nothing to worry about freeing the memory that is hold by the object, I will do that when I find that it will no longer used in program and JVM will manage me.»
I hope it clear the concept.
One of the reasons to do so is to eliminate obsolete object references.
You can read the text here.

Categories