How does Java garbage collector work here? - java

In this query remove() method has following implementation.
/**
* remove() removes "node" from this DList. If "node" is null, do nothing.
* Performance: runs in O(1) time.
*/
public void remove(DListNode node) {
if((node != null) && (node.listp == this)){
node.prev.next = node.next;
node.next.prev = node.prev;
}
this.size--;
}
After the execution of this remove() method, There would not be any inward pointer pointing to object unless the user of DList class still points to this node using some reference variable.
My question:
When and How does garbage collector trash this object after none of the reference pointers point to this object? Because How can GC get control of that object without any reference to it?

An object may be GC'ed/reclaimed at any point after it is no longer strongly reachable. An object is strongly reachable if and only if it can be reached (via strong references) from a GC root. That is, the GC reclaiming an object - if and when it chooses to do so - is merely a consequence of not being able to access said object.
Now, the one thing that Java guarantees is that it will try it's best (which may involve doing nothing) to free memory before throwing an OOM.
Even though there are no strong references from the code doesn't mean that the JVM isn't tracking the object or that it has vanished! The object still exists - even though it is not strongly reachable (read: not accessible) from user code - until/when such is actually GC'ed.
This allows for some interesting cases, eg.
A finalizer has a this - access to the object to be GC'ed! - and can "relife" (or "resurrect") objects, which is bad. Note: while a finalizer being called roughly implies the object is finally going to be GC'ed; a finalizer is not guaranteed to be called, ever, etc.
ReferenceQueues and the *Reference types can be used to track objects that are no longer strongly reachable and thus are elligble to be GC'ed even though a strong reference may still be obtainable - and obtaining such would remove the reclaimable status.

It is undefined. It could happen the next time the garbage collector runs (it can ONLY happy when the garbage collector runs), but that is not guarenteed - Not all garbage is necessarily cleaned with each gc run

Java's GC does not trash an object as soon as it's not used anymore. Instead, GC runs from time to time, checking objects' usage and emptying memory.
You cannot tell GC to run arbitrarily, but you can request it to run by calling System.gc(). However, calling gc() does not run GC AT THIS TIME... it will only request the System to run it.

Related

Java - HashMap and WeakHashMap references used in Application

Just trying to understand something from GC viewpoint
public Set<Something> returnFromDb(String id) {
LookupService service = fromSomewhere();
Map<String,Object> where = new WeakHashMap<>() {}
where.put("id",id);
return service.doLookupByKVPair(where); // where doesn't need to be serializable
}
what I understand is that once this method call leaves the stack, there is no reference to where regardless of using HashMap or WeakHashMap - but since weak reference is weakly reachable wouldn't this be GCd faster? But if the method call leaves the stack, then there is no reachable reference anyway.
I guess the real question that I have is - "Would using WeakHashMap<> here actually matters at all" - I think it's a "No, because the impact is insignificant" - but a second answer wouldn't hurt my knowledge.
When you use a statement like where.put("id",id); you’re associating a value with a String instance created from a literal, permanently referenced by the code containing it. So the weak semantic of the association is pointless, as long as the code is reachable, this specific key object will never get garbage collected.
When the entire WeakHashMap becomes unreachable, the weak nature of the references has no impact on the garbage collection, as unreachable objects have in general. As discussed in this answer, the garbage collection performance mainly depends on the reachable objects, not the unreachable ones.
Keep in mind the documentation:
The relationship between a registered reference object and its queue is one-sided. That is, a queue does not keep track of the references that are registered with it. If a registered reference becomes unreachable itself, then it will never be enqueued. It is the responsibility of the program using reference objects to ensure that the objects remain reachable for as long as the program is interested in their referents.
In other words, a WeakReference has no impact when it is unreachable, as it will be treated like any other garbage, i.e. not treated at all.
When you have a strong reference to a WeakHashMap while a garbage collection is in progress, it will reduce the performance, as the garbage collector has to keep track of the encountered reachable WeakReference instances, to clear and enqueue them if their referent has not been encountered and marked as strongly reachable. This additional effort is the price you have to pay for allowing the earlier collection of the keys and the subsequent cleanup, which is needed to remove the strongly referenced value.
As said, when, like in your example, the key will never become garbage collected, this additional effort is wasted. But if no garbage collection happens while the WeakHashMap is used, there will be no impact, as said, as the collection of an entire object graph happens at once, regardless of what kind of objects are in the garbage.

How finalizable objects takes at least 2 garbage collection cycles before it can be reclaimed?

I'm reading this article and I can't really understand how the finalizable objects (objects which override the finalize method) takes at least 2 GC cycles before it can be reclaimed.
It takes at least two garbage collection cycles (in the best case) before a finalizeable object can be reclaimed.
Can someone also explain in detail how is it possible for a finalizable object to take more than one GC cycle for reclamation?
My logical argument is that when we override finalize method, the runtime will have to register this object with the garbage-collector (so that GC can call finalize of this object, which makes me think that GC will have reference to all the finalizable objects). And for this, GC will have to keep a strong reference to the finalizable object. If that is the case then how this object became a candidate for reclamation by GC in the first place? I reach a contradiction by this theory.
PS: I understand that overriding finalize is not the recommended approach and this method is deprecated since Java 9.
You are right in that the garbage collector needs a reference to finalizable objects. Of course, this particular reference must not be considered when deciding whether the object is still reachable before the finalization. This implies special knowledge about the nature of this reference to the garbage collector.
When the garbage collector determines that an object is eligible for finalization, the finalizer will run, which implies that the object becomes strongly reachable again, at least as long as the finalizer is executed. After its finalization, the object must become unreachable again and this must be detected, before the object’s memory can be reclaimed. That’s why it takes at least two garbage collection cycles.
In case of the widely used Hotspot/OpenJDK environment (and likely also in IBM’s JVM), this is implemented by creating an instance of a special, non-public subclass of Reference, a Finalizer, right when an object, whose class has a non-trivial finalize() method, is created. Like with weak & soft references, these references are enqueued by the garbage collector when no strong reference to the referent exist, but they are not cleared, so the finalizer thread can read the object, making it strongly reachable again for the finalization. At this point, the Finalizer is cleared, but also not referenced anymore, so it would get collected like an ordinary object anyway, so by the next time the referent becomes unreachable, no special reference to it exists anymore.
For objects whose class has a “trivial finalizer”, i.e. the finalize() method inherited by java.lang.Object or an empty finalize() method, the JVM will take a short-cut and not create the Finalizer instance in the first place, so you could say, these objects, which make the majority of all objects, behave as if their finalizer did already run, right from the start.
Though you got your answer (which is absolutely correct), I want to add a small-ish addendum here. In general, references are of two types : strong and weak. Weak References are WeakReference/SoftReference/PhantomReference and Finalizer(s).
When a certain GC cycle traverses the heap graph and sees one of these weak references, it treats it in a special way. When it first encounters a dead finalizer reference (let's consider this being the first GC cycle), it has to resurrect the instance. finalize is an instance method, and it needs an actual instance to be invoked. So a GC first saw that this Object is dead, only to revive it moments later, to be able to call finalize on it. Once it calls that method on it, it marks the fact that it has already been called; so when the next cycle happens, it can be actually be GC-ed.
It would be incorrect to call this the second GC.
For example G1GC does partial clean-up of the heap (young and mixed), so it might not even capture this reference in the next cycle. It might not fall under its radar, as simple as that.
Other GCs, like Shenandoah, have flags that control on which iteration to handle these special references (ShenandoahRefProcFrequency, 5 by default).
So indeed there is a need for two cycles, but they do not have to be subsequent.

How does Java GC call finalize() method?

As far as I understand, GC starts with some set of initial objects (stack, static objects) and recursively traverses it building a graph of reachable objects. Then it marks the memory taken by these objects as occupied and assumes all the rest of the memory free.
But what if this 'free' memory contains an object with finalize method? GC has to call it, but I don't see how it can even know about objects that aren't reachable anymore.
I suppose GC can keep track of all 'finalizable' objects while they are alive. If so, does having finalizable objects make garbage collecting more expensive even when they are still alive?
Consider the Reference API.
It offers some references with special semantics to the GC, i.e Weak, Soft, and Phantom references. There’s simply another non-public type of special reference, for objects needing finalization.
Now, when the garbage collector traverses the object graph and encounters such a special reference object, it will not mark objects reachable through this reference as strongly reachable, but reachable with the special semantics. So if an object is only finalizer-reachable, the reference will be enqueued, so that one (or one of the) finalizer thread(s) can poll the queue and execute the finalize() method (it’s not the garbage collector itself calling this method).
In other words, the garbage collector never processes entirely unreachable objects here. To apply a special semantic to the reachability, the reference object must be reachable, so the referent can be reached through that reference. In case of finalizer-reachability, Finalizer.register is called when an object is created and it creates an instance of Finalizer in turn, a subclass of FinalReference, and right in its constructor, it calls an add() method which will insert the reference into a global linked list. So all these FinalReference instances are reachable through that list until an actual finalization happens.
Since this FinalReference will be created right on the instantiation of the object, if its class declares a non-trivial finalize() method, there is already some overhead due to having a finalization requirement, even if the object has not collected yet.
The other issue is that an object processed by a finalizer thread is reachable by that thread and might even escape, depending on what the finalize() method does. But the next time, this object becomes unreachable, the special reference object does not exist anymore, so it can be treated like any other unreachable object.
This would only be a performance issue, if memory is very low and the next garbage collection had to be performed earlier to eventually reclaim that object. But this doesn’t happen in the reference implementation (aka “HotSpot” or “OpenJDK”). In fact, there could be an OutOfMemoryError while objects are pending in the finalizer queue, whose processing could make more memory reclaimable. There is no guaranty that finalization runs fast enough for you’re purposes. That’s why you should not rely on it.
But what if this 'free' memory contains an object with finalize
method? GC has to call it, but I don't see how it can even know about
objects that aren't reachable anymore.
Let's say we use CMS garbage collector. After it successfully marked all live objects in a first phase, it will then scan memory again and remove all dead objects. GC thread does not call finalize method directly for these objects.
During creation, they are wrapped and added to finalizer queue by JVM (see java.lang.ref.Finalizer.register(Object)). This queue is processed in another thread (java.lang.ref.Finalizer.FinalizerThread), finalize method will be called when there are no references to the object. More details are covered in this blog post.
If so, does having finalizable objects make garbage collecting more
expensive even when they are still alive?
As you can now see, most of the time it does not.
The finalise method is called when an object is about to get garbage collected. That means, when GC determines that the object is no longer being referenced, it can call the finalise method on it. It doesn't have to keep track of objects to be finalised.
According to javadoc, finalize
Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.
So the decision is based on reference counter or something like that.
Actually it is possible not to have this method called at all. So it may be not a good idea to use it as destructor.

how to destroy an object in java?

I encountered this question in an interview with following options:
How to destroy an object in java?
a. System.gc();
b. Runtime.getRuntime.gc();
c. object.delete();
d. object.finalize();
e. Java performs gc by itself, no need to do it manually.
The answer should be e?
what if e was not there? then ?
clearly c is not the answer. a and b will do gc for the whole application(question requires for one object).
I think it is d because finalize() is called just prior to gc(but is it necessary that after finalize gc is invoked ?) or I am wrong ? e must be there to answer this question ?
Answer E is correct answer. If E is not there, you will soon run out of memory (or) No correct answer.
Object should be unreachable to be eligible for GC. JVM will do multiple scans and moving objects from one generation to another generation to determine the eligibility of GC and frees the memory when the objects are not reachable.
To clarify why the other answers can not work:
System.gc() (along with Runtime.getRuntime().gc(), which does the exact same thing) hints that you want stuff destroyed. Vaguely. The JVM is free to ignore requests to run a GC cycle, if it doesn't see the need for one. Plus, unless you've nulled out all reachable references to the object, GC won't touch it anyway. So A and B are both disqualified.
Runtime.getRuntime.gc() is bad grammar. getRuntime is a function, not a variable; you need parentheses after it to call it. So B is double-disqualified.
Object has no delete method. So C is disqualified.
While Object does have a finalize method, it doesn't destroy anything. Only the garbage collector can actually delete an object. (And in many cases, they technically don't even bother to do that; they just don't copy it when they do the others, so it gets left behind.) All finalize does is give an object a chance to clean up before the JVM discards it. What's more, you should never ever be calling finalize directly. (As finalize is protected, the JVM won't let you call it on an arbitrary object anyway.) So D is disqualified.
Besides all that, object.doAnythingAtAllEvenCommitSuicide() requires that running code have a reference to object. That alone makes it "alive" and thus ineligible for garbage collection. So C and D are double-disqualified.
Short Answer - E
Answer isE given that the rest are plainly wrong, but ..
Long Answer - It isn't that simple; it depends ...
Simple fact is, the garbage collector may never decide to garbage collection every single object that is a viable candidate for collection, not unless memory pressure is extremely high. And then there is the fact that Java is just as susceptible to memory leaks as any other language, they are just harder to cause, and thus harder to find when you do cause them!
The following article has many good details on how memory management works and doesn't work and what gets take up by what. How generational Garbage Collectors work and Thanks for the Memory ( Understanding How the JVM uses Native Memory on Windows and Linux )
If you read the links, I think you will get the idea that memory management in Java isn't as simple as a multiple choice question.
Set to null. Then there are no references anymore and the object will become eligible for Garbage Collection. GC will automatically remove the object from the heap.
Here is the code:
public static void main(String argso[]) {
int big_array[] = new int[100000];
// Do some computations with big_array and get a result.
int result = compute(big_array);
// We no longer need big_array. It will get garbage collected when there
// are no more references to it. Since big_array is a local variable,
// it refers to the array until this method returns. But this method
// doesn't return. So we've got to explicitly get rid of the reference
// ourselves, so the garbage collector knows it can reclaim the array.
big_array = null;
// Loop forever, handling the user's input
for(;;) handle_input(result);
}
In java there is no explicit way doing garbage collection. The JVM itself runs some threads in the background checking for the objects that are not having any references which means all the ways through which we access the object are lost. On the other hand an object is also eligible for garbage collection if it runs out of scope that is the program in which we created the object is terminated or ended.
Coming to your question the method finalize is same as the destructor in C++. The finalize method is actually called just before the moment of clearing the object memory by the JVM. It is up to you to define the finalize method or not in your program. However if the garbage collection of the object is done after the program is terminated then the JVM will not invoke the finalize method which you defined in your program.
You might ask what is the use of finalize method?
For instance let us consider that you created an object which requires some
stream to external file and you explicitly defined a finalize method to this object which checks wether the stream opened to the file or not and if not it closes the stream. Suppose, after writing several lines of code you lost the reference to the object. Then it is eligible for garbage collection. When the JVM is about to free the space of your object the JVM just checks have you defined the finalize method or not and invokes the method so there is no risk of the opened stream. finalize method make the program risk free and more robust.

Java - when is this object unloaded?

Here is my code:
LinkedList <Mono> list = new LinkedList ();
list.add(new Mono (2, 2));
list.add(new Mono (1, -1));
list.remove (1);
Now, when the second item in the list is removed, is the object destroyed? IE, it undergoes garbage collection?
EDIT for new question:
Yes, the object will be eligible for garbage collection when there are no strong references remaining. However the JVM will try to do clean up garbage in big batches, so it could actually get collected at any arbitrary later time (or never if the JVM terminates before GC gets around to it)
Old answer:
Class unloading is a rare event, and will generally not happen in a timely manner (if at all.)
Specifically, even after it becomes eligible for collection it won't get collected along with "normal" new objects like your Mono instances - it's often in a special different pool (PermGen in the Oracle JVM)
You should assume that once a class is loaded it will stay loaded forever. Once you get into web applications in containers this is not always true, but anyone that has worked in those environments can tell you generally how well it (doesn't) work.
Garbage Collection in Java is generally non-deterministic insofar as when it will occur and which eligible objects the GC will evict ("free") when a GC cycle does occur.
The only reliable rule is thus:
An object will remain available (will not be GC'ed/freed/evicted) as long as it is strongly-reachable. (See "The Reachability Lifecycle of Objects" in Chapter 9 of Inside the Java Virtual Machine for what this means -- very good reading in general, if a tad dated.)
In the posted code the remove will result in the second object new Mono(1, -1) being eligible for reclamation as there are no longer any strong references to it (the object is no longer strongly-reachable). The actual eviction (if it occurs) will happen "sometime later" and may not even be the next GC cycle. Using finalizers (ick) further complicates the matter.
Note that an object is never guaranteed to be GC'ed (the JVM may just terminate [ab]normally, for instance) and the exact semantics of particular GC implementation can differ and still be a conforming virtual machine -- it all comes down to reachability.
Happy coding.
Do you mean when the Object is unloaded?
An empty list is still a list, so it'll stay in memory. It is cleared when you go:
list=somethingElse;
That is assuming that you don't assign anything else to be list.
As far as the class definition itself, it should stay in memory forever. Class definitions are in the permanent generation.
As a side note. list cannot be garbage collected at that point. Because you can add things to it after if you clear it.
the second object will be elligible for gargabe collection after removing it from the list, since there will be no more references to it .. hence out of scope .
hope this helped
Lots of answers, so here's my spin. Think about "scope", a concept in computer languages that describes where and when you can access a named bit of memory.
Here's your original code, with your purported removal of the second list member added:
LinkedList <Mono> list = new LinkedList ();
list.add(new Mono (2, 2));
list.add(new Mono (1, -1));
list.remove (1);
list.remove (2);`
At the point of list.remove(2), the object "list" can still be referenced. Sure, it's empty, but then you might decide to add a new Mono to it. You can because "list" is still in scope, so "list" is not reclaimed.
Compare to this:
{
LinkedList <Mono> list = new LinkedList ();
list.add(new Mono (2, 2));
list.add(new Mono (1, -1));
list.remove (1);
list.remove (2);`
}
After the closing brace, "list" can no longer be referenced. "list" was declared inside that scope, and when the scope was exited, "list" was removed from the namespace along with the scope itself. At that point, garbage collection could happen, since no one could possibly use "list" again.
Keep an eye on the scope of your objects. If you want to influence garbage collection, keep the scope of your objects limited to the region where they are used. As it happens, that is good programming style too.
I guess people got confused with the terminology you used. I believed you are asking if your Mono object will be "deleted"/"garbage collected".
Let's take a look at the remove(1) that you are invoking...
This is the remove function that you are calling as defined in java.util.LinkedList:
public E remove(int index) {
return remove(entry(index));
}
The function above calls the following (look at my comments in the code):
private E remove(Entry<E> e) {
if (e == header)
throw new NoSuchElementException();
E result = e.element;
e.previous.next = e.next; //Preceding element refers now to the one after the element to be removed;
e.next.previous = e.previous; //Next element refers now to the one before the one to be removed;
e.next = e.previous = null; //Element to be removed doesn't refer to anything anymore;
e.element = null;
size--;
modCount++;
return result;
}
After the function you call terminates, there is no way to refer to your Mono(1, -1) anymore. That Mono Object is not accessible anymore. This means that it will become eligible for Garbage Collection. Keep in mind that "eligible" might mean that it never be garbage collected... More on GC here.
The simple answer is that it should not matter to you when a Java object is garbage collected. The only thing that you need to know is that it will get garbage collected before your program runs out of memory ... provided that the object is unreachable.
The complicate answer includes other things:
The garbage collector typically runs at a time that you can't predict.
You can call System.gc() to suggest that the JVM runs the GC run now, but:
the JVM may ignore this hint, and
it is generally a bad idea to do this. (Running the GC is expensive, and your application has insufficient information to know when it is best to do this from an efficiency standpoint.)
Any particular run of the GC is not guaranteed to reclaim all unreachable objects. The GC has a lot of "smarts" that are aimed at making GC as efficient as possible, or reducing "pause" times. One of the "smarts" is to not GC the entire heap every time.
There are no guarantees that the GC will run at all, or that it will run before the JVM is shutdown.
Because of the above, it is a bad idea to write an application so that it depends on a specific object being reclaimed / deleted at a specific time.
(The one thing that should concern you in memory management is storage leaks; e.g. when your application keeps references to unwanted objects that prevent those objects from ever becoming unreachable. But that's not what your question is about.)
The class "Mono" cannot be unloaded since there are still references to it. The type of the list refers to it and there is still one element in the list.
I suppose you did not mean to ask whether the class is unloaded, but whether the instance is "unloaded". Each instance of a class, each object, is allocated on the heap. When the object is no longer in use, the space that it occupies in the heap can be reclaimed. This does not happen immediately however. All JVM implementations that I know use a garbage collector to clean up the memory. To really simplify things here: when there is no more space free to create a new object on the heap, the garbage collector kicks in and will check which parts of the heap are still in use. The parts that are no longer in use, can be reused for new objects.
So, the memory from an object that is no longer in use, will only be reclaimed when the garbage collector kicks in. And this is something that cannot be predicted.
Do you mean is the instance of Mono eligible for garbage collection or is the instance of list eligible for garbage collection?
The instance of mono will be eligible for garbage collection when it is removed (assuming that the code has not created over references to it.
The list is NOT eligible for garbage collection just because it is emptied. An empty list cannot be garbage collected because it is a valid object that can read and written to again.
An as others have pointed out. We are talking about eligible for garbage collection. The garbage collector does not necessarily run immediately.

Categories