I have some question about Java garbage collection.
Below is the code of some test class
public class ChildMaker{
public Child createChild(){
Child c = new Child();
return c;
}
}
And the actual test I'm performing
public class TestChildMaker{
public getChild(){
ChildMaker maker = new ChildMaker();
Child c = maker.createChild();
....
}
}
I wonder if the ChildMakerinstance can be garbage collected. Can it ?
The Java garbage collector is sophisticated, and likes to work fairly autonomously. You can't force it to garbage collect anything, and you can only give it an indication of when it might like to garbage collect.
Any object to which a reference is still held in your program (strictly: by any thread that could still run) cannot be garbage collected. Anything else could be.
I think you're asking whether the ChildMaker instance can be garbage collected while the Child is still referenced. Strictly speaking such a position does not exist in the code that you provided. The answer is yes; if the ChildMaker is unreferenced then it can be garbage collected even if the Child is still referenced, because the Child does not hold a reference to the ChildMaker.
The answer depends on what happens
public getChild(){
ChildMaker maker = new ChildMaker();
Child c = maker.createChild();
.... // here <--------
}
If the variable maker is reused, the object it references is reachable and can therefore not be garbage collected. If maker is not reused, then the object is no longer reachable and can therefore be garbage collected.
The Java Language Specification states
A reachable object is any object that can be accessed in any potential
continuing computation from any live thread.
Related
When does the object of type list, occupying memory, become eligible for garbage collection, Also where is the variable that holds reference to the list ? In the case of code below, there was no variable assigned to it.
CASE 1:
for (Integer i : returnList()) {
System.out.println(i);
}
In case of a code like:
CASE 2:
List list = returnList();
for (Integer i : list) {
System.out.println(i);
}
list = null;
We can take control of GC, Is there any ways to take care of that in the first case when no variable was assigned ?
To summarize:
What is the mechanism of referrence, without a reference variable to list is case 1?
Does list get eligible for GC'd when stack frame is popped ?
Any way to speed up the eligibility for GC'ing ?
What is the mechanism of referrence, without a reference variable to list is case 1?
There is an implicit reference to the list. This can be seen by understanding that enhanced for like that is translated into:
for(Iterator e = returnList().iterator(); e.hasNext(); ) {
Integer i = (Integer)e.Next();
System.out.println(i);
}
Here, e has a reference to an iterator on returnList, which itself has a reference to returnList. Thus, returnList is rooted as long as e is rooted which is only true while control is in the for loop. When control leaves the for body, e is eligible for collection, so returnList is eligible for collection.
Of course, all of this is assuming that
The owner of returnList isn't maintaining a reference to its return value.
The same list hasn't been returned to another caller and that other caller isn't maintaining a reference to the same list.
Does list get GC'd when stack frame is popped ?
Not necessarily. It will be eligible for collection when the JVM can determine that the referrent has no rooted references to it. Note that it does not necessarily immediately get collected.
Any way to speed up GC in case 1.
It can't be collected any sooner than control leaving the for loop. It might be collected after control leaves the for loop. Let the JVM worry about this.
Note that you can attempt a manual garbage collection via
System.gc();
but note that this might exhibit worse behavior because if it triggers a garbage collection, it might be a full garbage collection. Note that the JVM can ignore this request. You might be wasting a lot of CPU cycles here. Note that on a system with infinite memory, the garbage collector never needs to run. On such a system, requesting the garbage collector could be a complete waste of CPU cycles if the garbage collector obeys your request.
Let the JVM manage the garbage collections. The algorithms for it are highly tuned.
From SCJP page 256-257
The garbage collector does some magical, unknown operations, and when
it discovers an object that can't be reached by any live thread,it
will consider that object as eligible for deletion, and it might even
delete it at some point. (You guessed it; it also might not ever
delete it.) When we talk about reaching an object, we're really
talking about having a reachable reference variable that refers to the
object in question. If our Java program has a reference variable that
refers to an object, and that reference variable is available to a
live thread, then that object is considered reachable.
Setting an object to NULL might help to fasten when the GC deletes the object but it might as well not, you don't have control over that. The JVM will run GC when it senses that memory is running low and you can manually ask it to do so but nothing is guaranteed.
What is the mechanism of reference, without a reference variable to
list is case 1?
see next answer.
Does list get GC'd when stack frame is popped ?
The list is created on the heap - but if the only reference to it was on the stack it is eligible to be collected by GC. That doesn't mean that it'll happen any time soon though.
Any way to speed up GC in case 1.
You can't "speed up" GC, even by calling System.gc(); you're only "suggesting" that the GC can to do its work - again, it won't necessarily happen any time soon.
There's a lot of sense behind it too: say that your program has 2GB of memory to use and is currently using only 2KB - it does not justify GC stopping your program from running and clean the memory only because some objects are eligible for deletion.
You cannot take control of GC.It is managed by JVM. What you can manage is what objects should be available for garbage collection. Although , you can find out when garbage collector will run using finalize method. It is always called before an object is deleted
public class Demo{
static void create()
{
Demo o = new Demo();
}
public void finalize()
{
System.out.println("GC called");
}
public static void main (String ...ar)
{
for (long i=1;i<900000;i++) //Try changing values here
{
create();
}
}
}
Objects created inside the methods are available for GC when method is returned(just like local variables exist for duration of method).However if the method returns an object, it will not be avialble for garbage collection
public class Demo{
public void getDate()
{
Date o = new Date();
StringBuffer d = new StringBuffer(o.toString());
System.out.println(d);
return o;
}
public static void main (String ...ar)
{
Date x= getDate();
}
}
In the above code, object d is available for GC when the method returns. But object o will not be available for collection
For example
public void doSomething() {
Dog smallDog = new Dog();
smallDog.bark();
}
will the dog object be collected after this method is run?
It can become eligible to be collected when the method returns. When garbage collection actually happens is some unknown time in the future.
It is impossible to tell for sure without seeing the implementation of bark().
If this is your bark:
public void bark() {
BarkListeners.callBack(this);
}
public class BarkListeners {
private static final List<Dog> barkers = new ArrayList<Dog>();
public static void callBack(Dog dog) {
barkers.add(dog);
}
}
Then no, it won't be getting garbage collected!
Simply no. I mean, the timing does not have to be like that.
All Java Objects are allocated in the heap and collected by the GarbageCollector. And GarbageCollector runs in background, with almost no constraint on when to perform actual garbage collection.
Technically, it isn't possible to give and answer because we haven't seen the implementation for Dog#bark().
Generally, the answer is YES, the Dog instance will be collected AFTER the method is run, it just isn't possible to know exactly when. The reason for this is that unless the bark method shares the reference to the Dog object with another object, the particular instance of Dog will no longer be reachable. The next time the Garbage Collector runs, it will determine that Dog is not reachable and collect the heap space that was used to keep it.
It depend on reach ability of the object. If object is not reachable then it is eligilble for GC. When to GC is dependent on JVM implementation. Truth About Garbage Collection
This blog post provides a good explanation on how the garbage collection process works. To summarize:
An Object becomes eligible for Garbage collection if its not reachable from any live threads or any static refrences. It (the Garbage Collector) will only trigger if JVM thinks it needs a garbage collection based on Java heap size.
Therefore you shouldn't make assumptions on when any object will be garbage collected.
If I have code similar to the following:
public Constructor(final Object o) {
taskSystem.add(new CycleTask(15, 15, -1) {
#Override
public void execute() throws Throwable {
//access o here every 15 cycles forever
}
});
}
When would o be garbage collected, if ever? Only when the task has been collected, or will it remain in memory forever because it's final?
o might get garbage collected once it is not reachable any longer, whether it is final or not. Obviously, as long as execute is running, if it needs to access o, it will prevent GC.
When execute is done running, and assuming you have not stored any references to o (for example in a collection), it will be flagged as ready for garbage collection.
When the anonymous class instance becomes eligible for garbage collection, if nothing else refers to the object that o referred to when the method was called, that object will become eligible for garbage collection.
There's nothing special about final variables which deters garbage collection.
'final' has no effect on GC. The object will become eligible for collection when it becomes unreachable. In this case there are at least three references, any one of which can stop that: the 'final' parameter, which disappears when the method returns; the caller's reference; and the copy of the final variable in the anonymous class instance.
There is no relationship between final keyword and the lifetime of the variable.
It will be garbage collected when not needed anymore, and since it's a parameter this can happen just outside the method (if there is no reference outside).
The final keyword is just a constraint given to the compiler to forbid any further modification of the reference o after the call of the function.
The following snippet from RuntimeUtil.java from jlibs guarantees GC that garbage collection is done.
Since, it also uses System.gc(), i dont understand how can they guarantee that it will happen 100% of the times.
Following is the snippet:
/**
* This method guarantees that garbage collection is
* done unlike <code>{#link System#gc()}</code>
*/
public static void gc(){
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get()!=null)
System.gc();
}
Its related with Strong Reference & Weak Reference with respect to Garbae Collection.
A strong reference is an ordinary Java reference, the kind you use every day.
If an object is reachable via a chain of strong references (strongly reachable), it is not eligible for garbage collection. As you don't want the garbage collector destroying objects you're working on, this is normally exactly what you want.
A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability
The gc() method in the pointed class works on this concept.
/**
* This method guarantees that garbage collection is
* done unlike <code>{#link System#gc()}</code>
*/
public static void gc(){
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get()!=null)
System.gc();
}
Once a WeakReference starts returning null, the object it pointed to has become garbage and the WeakReference object is pretty much useless. This generally means that some sort of cleanup is required;
That's why they guarantee that it will happen 100% of the times.
From what I can see it should work as they
1) create an object
2) get a "weak" reference to it
3) null the reference to it, in order to mark it for garbage collection
4) and wait with the while loop until it actually disappears
A single call to System.gc() does not guarantee all objects that are eligible for garbage collection are re-claimed. See How to cause soft references to be cleared in Java?
In this case, the garbage collection is run many times till a an weak object ref is returning null. I doubt efficacy of this approach. There will be many other objects that may be garbage collected. To me it (jlib) does not have any thing to learn from.
For example the code in the library written in 2009. (extracted)
/**
* This method guarantees that garbage colleciton is
* done after JVM shutdown is initialized
*/
public static void gcOnExit(){
Runtime.getRuntime().addShutdownHook(new Thread(){
#Override
public void run(){
gc();
}
});
}
Why to you need gc when shutdown is called? The library quoted in question is pure garbage.
Suppose you have an instance a of Class A. Is it possible to create an instance b of class B, such that when a is garbage collected b will be garbage collected?
I know can cheat and create a reference to a in b, so a has to wait for b or something. What I want is for instance b to be deleted when a would naturally be deleted.
No. You can never force any object to be garbage collected. That's rather the point of garbage collection.
However, if the only reference to b is from a, then it is very likely that when the collector collects a, it will also collect b.
But to be honest, if you're worrying about when objects will be collected, the chances are you've doing it wrong. There should be no difference between dead and deleted objects as far as your program is concerned. Do you have a specific use for this that you would like to discuss?
As you might know, we cannot force GC to work according to our wish.
But the first thought which can to mind was if A contains the instance of B, then naturally when a is GCed, b will be, too. This is just one scenario which came to my mind. I don't how you actually want to do it.
You can also use weak references.
Usually, you can't even be sure when a object is collected (even System.gc() does not ensure that all unreferenced objects are collected) it is up to the garbage collection algorithm to decide if an unreferenced object is collected.
There are several GC strategies (you can set it when starting the JVM), your only option is to chose one that is exhaustive so it ensures that all unreferenced objects are collected(*). Then you'll have to be sure that both a and b get unreferenced at the same time (and that the gc is not called in between -I do not know of any way to ensure that-).
(*) Don't know if such algorithm does even exist. But if it does I am pretty sure it will have a heavy impact in performance.
Yes it is possible, if the instance of B is inside class A, it will get garbage collected automatically when A is destroyed. This example can be implemented this way:
public class A {
` B b;
public A(B b) {
this.b =b;
}
}
public class Test() {
public static void main(String [] args) {
A a = new A();
}
}
When a goes out of scope, both a and b will get garbage collected(object b inside a will be garbage collected first).
I don't think you can call garbage collector for an specific object, it works automatically as needed(You cant force that). You can try to invoke it this way:
Runtime r = Runtime.getRuntime();
r.gc();
It is not guaranted that the objects will be garbage callected when you execute the above code(Maybe the garbage collector is bussy)
There are no events fired when an object is finalized, except a (non-guaranteed) call to obj.finalize().
You may place some code to finalize() of A. If you can somehow deduct the object B based on object A data (but not keeping an actual reference), you may at this point remove B from a global static Set, making it eligible for GC (not necessary at the same GC run though).