Interview Question on Java finalize method - java

I have came across difficult (for me) Java interview question on finalize method. Suppose you have given finalize method as shown below:
public void finalize()
{
a.b = this;
}
Now the following object scenario is given.
How would you solve this problem? If A was not referring to B then this problem could be easier as GC will run, it will collect B and call finalize for B but here A is referring B so its difficult. How finalize will work in this scenario?
Any ideas? Thanks in advance

The easiest way to think of Java finalization is to consider it an extra 'bit' of state that every object with a finalizer has. When a new object is created, this isFinalized bit is set to false. When the garbage collector finds that an object with a finalizer is unreachable, it checks this isFinalized bit and only reclaims the object if it is true -- if it is false it instead runs the finalizer and sets the bit to true. Once set, there's no way for the bit to ever be cleared, so in any later time the garbage collector runs, if it's unreachable, it will be collected.

Very interesting question. From the JDK1.6 Doc, I find these two sentences:
1. The finalize method may take any action, including making this object available again to other threads
2. The finalize method is never invoked more than once by a Java virtual machine for any given object.
So in my opinion, for the first time, when B is collecting by GC, finalize method will be invoked if A is still available to some threads then B becomes available again, this time the GC will not collect B. But because finalize method will be invoked only once, so next time when the GC find B can't be accessed by any thread then GC will collect B.

It is not entirely clear what you are asking.
However, the JLS 12.6.2 states that the order in which objects are finalized is not specified. This means that the finalize methods for all finalizable classes should be designed to work when invoked in any order.
Note that this applies equally to unreachable and finalizer-reachable objects. In other words, the 3 objects in your diagram could be finalized in any order.
... how B will be garbage collected as A is reachable and how finalize will get called for B?
Perhaps it is a trick question. If A is reachable, then B is also reachable, so it won't be garbage collected, and its finalize method won't be called. If A becomes unreachable then so does B, and both will be finalized.
What that finalize method will actually do depends on what class it belongs to. Lets assume it is a method of the "guaranteed reachable object", and the a variable contains a reference to A:
The finalize method won't be called by the GC because the object is reachable.
Some other code could explicitly call that finalize method. If that happened, then a.b will no longer refer to B, and B will be unreachable and eligible for eventual garbage collection, finalization and (ultimately) deletion.

Sorry if I am wrong. But to me, B is a field of A, so A definitely need to keep a reference to B, and while A "always-live" object holding a reference to A, both A and B will not be GC and the problem to GC B is just not making any sense.

Related

Can the finalize() method be called twice if the garbage collector retains memory twice in the same code?

I found it in many places that the finalize() method in java is called when the garbage collector or System.gc() has successfully retained the memory consumed by the redundant object with no more references to it. Also found that this method is called not more than a single time. I am not new to java but also not pretty much experienced. I may have a wrong understanding of it but let's say a piece of code
public class Solution {
#Override
protected void finalize(){
System.out.print("method called");
}
public static void main(String... args){
Solution obj1= new Solution();
Solution obj2 = new Solution();
Solution obj3 = new Solution();
System.gc();
obj1=obj2;
System.gc();
obj3=null;
System.gc();
}
}
Here, the finalize method is called twice because the memory heap becomes eligible for garbage cleaning two times. So, I am a bit confused whether I know the whole thing right or if it is supposed to behave the way it's behaving.
No. The finalize() method will only be called once by the GC on an object. The JVM sets a flag in the object header (I think) to say that it has been finalized, and won't finalize it again.
The javadoc states this explicitly:
" The finalize method is never invoked more than once by a Java virtual machine for any given object. "
Of course, there is nothing to stop an object method from calling this.finalize() any number of times.
Note that finalize() is deprecated in Java 9 and later for reasons stated in the javadoc. It is recommended that you switch to using one of the following instead:
AutoCloseable + try with resources
Cleaner
PhantomReference
Someone commented thus:
finalize() is called for every Object that is collected.
This is not true for a couple of reasons.
The javadoc explicitly states that there are no guarantees that finalize will ever be called. The thing that is guaranteed is that it will be called (once) before an object's storage is reclaimed. That is a weaker statement than the statement that the comment makes.
One scenario where garbage collected objects may not be finalized is if the JVM exits soon after a GC run.
Another (pathological) scenario occurs when a classes finalize method never returns1. When an instance of that class is finalized, the finalizer thread will get stuck. When all finalizer threads are stuck in that way, no more finalizable objects can be finalized2.
If the Object::finalize is not overridden in a class, the JVM will skip the finalization step for that class.
1 - This could be due to an infinite loop, or because the finalize() method gets stuck waiting on a lock or waiting for an internal or external "event" that never happens. Note also that "never" could mean "not for a long time" in this context. The overall impact can be the same.
2 - The objects will sit in the finalization queue indefinitely. This is a memory leak.

How to log when the finalize method was not called?

I am not using the finalize method in my application but this question is out of curiosity.
Assume that there is finalize method in a class and I would like to log a warning message that finalize was not called.
How to do this ?
Any tips ?
Two possibilities--In either case, you need a singleton collection.
1) When each object is constructed add a unique key (String) that identifies the object--(but not the object itself!) to the collection. When the finalizer is called, remove it's key from the collection.
At any given time, outstanding instances are available in the collection.
2) Okay, you CAN add the object itself to the collection if you really want to, but the collection must be a collection of the proper reference class. This is harder and requires a little research--look into reference classes (WeakReference/PhantomReference/??). I haven't looked at them for a few years and forget exactly which one does what, but this is exactly the kind of work the Reference classes were made for.
Be careful with 2, I think there is a chance that iterating through the reference collection could resurrect a dead class or stop one from being collected.
The reason for both caveats is that if you store a reference in a normal collection it will never be eligible for collection so no finalizer will ever be called.
The JVM guarantees that the method will be called before the object is disposed, as per JLS 12.6. Finalization of Class Instances:
The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.
You are trying to prove that JVM does not follow the JLS, which would be a bug.
Looking at Azul Zulu OpenJDK 11 source we can observe that finaliztions are run with java.lang.ref.Finalizer object which in turn uses jdk.internal.misc.JavaLangAccess.invokeFinalize(Object) method to call Object.finalize().
JavaLangAccess instance is obtained from jdk.internal.misc.SharedSecrets which allows to setup a custom instance of JavaLangAccess. Perhaps you could create your own JavaLangAccess instance with additional logging in invokeFinalize() method?

Meaning of ReferenceQueue

I try to understand class ReferenceQueue
It is optional constructor argument for
SoftReference
and
WeakReference
Also it is mandatory argument for PhantomReference.
According information I have read I can write some thesises
a)for PhantomReference method get always returns null
b)
for Phantom references:
1. gc detect that object can be deleted from memory
2. reference to the object puted to the ReferenceQueue
when we invoke clear or link to reference from queue becaom unreachable and gc see that
3. finalize methods invokes
4. free memory
for weak/soft references:
1. gc detect that object can be deleted from memory
2. finalize methods invokes
3. free memory
4. reference to the object puted to the queue
When can I pass second argument to XXXReference constructor?
Which help I can get?
Why PhantomReference has not constructor without ReferenceQueue ?
What the reason to have ReferenceQuee which get methods returns null always?
Maybe, the following program helps a bit:
public class SimpleGCExample {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue<Object> queue=new ReferenceQueue<>();
SimpleGCExample e = new SimpleGCExample();
Reference<Object> pRef=new PhantomReference<>(e, queue),
wRef=new WeakReference<>(e, queue);
e = null;
for(int count=0, collected=0; collected<2; ) {
Reference ref=queue.remove(100);
if(ref==null) {
System.gc();
count++;
}
else {
collected++;
System.out.println((ref==wRef? "weak": "phantom")
+" reference enqueued after "+count+" gc polls");
}
}
}
#Override
protected void finalize() throws Throwable {
System.out.println("finalizing the object in "+Thread.currentThread());
Thread.sleep(100);
System.out.println("done finalizing.");
}
}
On my system, it prints
weak reference enqueued after 1 gc polls
finalizing the object in Thread[Finalizer,8,system]
done finalizing.
phantom reference enqueued after 2 gc polls
or
finalizing the object in Thread[Finalizer,8,system]
weak reference enqueued after 1 gc polls
done finalizing.
phantom reference enqueued after 2 gc polls
The order of the first two messages occasionally differs due to the multi-threading. And sometimes, the phantom reference is reported to be enqueued after three polls, indicating that it took more than the specified 100 milliseconds.
The key point is
soft and weak references are cleared and enqueued before or right when starting finalization
phantom references are enqueued after finalization, assuming that the object has not leaked the finalize method, otherwise they are enqueued after the object has become unreachable again
the presence of a (non-trivial) finalize() method causes the need of at least one additional garbage collecting cycle to detect that the object is unreachable or phantom reachable again
Since more than 99% of all objects don’t need finalization, all JVM vendors are strongly encouraged to detect when finalize() has not been overridden or is “trivial”, i.e. an empty method or a sole super.finalize() call. In these cases, the finalization step should be elided. You can easily check that this optimization happens in your JVM, by removing the finalize() method in the above example. Then it prints
weak reference enqueued after 1 gc polls
phantom reference enqueued after 1 gc polls
Since both are enqueued at once and retrieved in an arbitrary order, the order of the two messages may differ. But they are always both enqueued after one gc cycle.
It’s worth noting that the fact, that phantom references are not automatically cleared, implies that it takes another garbage collection cycle until the object’s memory really can be reused, so the above example requires at least three cycles with the non-trivial finalize() method and two without. Java 9 is going to change that, clearing phantom references automatically, so in the above example it will take two cycles with finalization and one without until the memory really can be reclaimed. Well, to be precise, in this simple example the object’s memory will never be reclaimed as the program terminates before that can happen.
The code above also demonstrates one of the intended use cases of the Reference API. We can use it to detect when an object’s reachability changed within code under our full control, e.g. using a loop within the main method. In contrast, finalize() may be called by a different, unspecified thread at an arbitrary time. The example also shows that you can draw information from the reference object without needing the get() method.
Practical applications often use subclasses of the reference classes to add more information to them. This is what happens with WeakHashMap.Entry which extends WeakReference and remembers the hash code and value. The cleanup can be done within the normal map operations, not needing any thread synchronization. This would not be possible with a finalize() method, besides the fact that the map implementation can’t push a finalize() method into the class of the keys.
This is meant with the “more flexible than finalization” term.
The WeakHashMap demonstrates how the get() method can be useful. As long as the key hasn’t been collected, it will be reported as being in the map and can be retrieved when iterating over all keys or entries.
The PhantomReference.get() method has been overwritten to always return null to prevent that an application can resurrect the referent of an enqueued reference. This is a direct consequence of the “phantom references are not automatically cleared” rule. That rule itself is questionable and it’s original intention lies in the dark. While the rule is about to be changed in the next Java version, I’m afraid that get() will continue to always return null to be backwards compatible.
1) When can I pass second argument to XXXReference constructor?
You can do it whenever you like. You should do it whenever you need the references to be processed as they are being broken.
2) Which help I can get?
I don't understand this questiom
3) Why PhantomReference has not constructor without ReferenceQueue ?
The purpose of PhantomReference is to be a more flexible alternative to regular finalization. However, in order for that to work, the references must be enqueued for the finalization-replacing code to work. (A PhantomReference that was not enqueued could not be processed.)
By contrast SoftReference and WeakReference objects are often useful without being enqueued.
4) What the reason to have ReferenceQueue which get methods returns null always?
The ReferenceQueue API doesn't have a get() method, so I guess you are talking about the PhantomReference API. The reason that there is a get() method is for compatibility with the superclass. The reason that get() is defined to return null is as follows:
"In order to ensure that a reclaimable object remains so, the referent of a phantom reference may not be retrieved: The get method of a phantom reference always returns null."
(See the javadoc.)
In other words, it is done to make it impossible to "resurrect" the referent.
UPDATE
In fact, all of the Reference classes will clear the referent before enqueuing a Reference. (Actually, the GC itself does this directly.) Application code that pulls references from a ReferenceQueue cannot use the get() method to identify the (now deleted!) referent. They must do it some other way; e.g. based on the identity of the Reference object.
What distinguishes a phantom reference is that the get() method always returns null. (So the explanation in the javadoc is ... unconvincing.)

On Java garbage collection, clarification needed

Upon new A(), we allocate sufficient amount of memory to hold all object that A contains.
Object A() may contain other objects like B() and C()
Question 1: When A() is no longer needed and you want to remove it from the heap, will setting it's reference to null do the trick? (If not, what would be the right way to signal the JVM to GC this object now?)
Question 2: If so, what happens with the instances pointing to B() and C()
Question 3: Is there a way this effect can be observed? (memory being deallocated to free up the object)
Setting A to null will mark A as a candidate to be freed by the GC. Instances of B and C will be marked too if the only references to those instances were from instance A.
Edit about question 3: A simple way to debug this effect is using the method finalize; When an object is GC´ed, his finalize is called .
However, be careful with this method: finalize is not guaranteed to be executed always (as the GC is not guaranteed to free an object) and should never be used for application´s general purposes.
There are better debugging tools depending on your IDE. For example, in eclipse: http://www.yourkit.com/docs/80/help/garbage_collection.jsp
If you have live reference to B and C then it won't GCed
at any point if any object doesn't have live reference to it, that object is ready to be GCed
class A{
B b = new B();
C c = new C();
}
now when you do
A a = new A();
a= null;//instance referred by a,b & c are ready to be collected in this system
Object A() may contain other objects like B() and C()
Objects only contain primitives and refrences to other objects.
Question 1: When A() is no longer needed and you want to remove it from the heap, will setting it's reference to null do the trick?
It is rarely needed but you can do this.
Question 2: If so, what happens with the instances pointing to B() and C()
Nothing, they are unrelated objects.
Question 3: Is there a way this effect can be observed? (memory being deallocated to free up the object)
You can override the finalize() method or use ReferenceQueues. This only informs you about collected object rather than discard objects. Its best to avoid needing to do this.
Objects which do not have a strong reference from root context e.g. thread stacks, can be collected. It doesn't matter how this happens. Setting a reference to null can allow this to happen, but more often allowing a variable to go out of scope is a simpler way to discard an object(s).
If you have Object B and it points to C which points to B and there are no other references to these objects, they will still be cleaned up even though there are references to those objects.
You cannot force GC to delete an object. GC will automatically delete any objects that are safe to be deleted. You can force GC to run by invoking System.gc(), which will delete any objects it can.
A = null will delete the object only if no other references to that object exists.
In general GC exists so you don't have to worry about deletion and memory collection. If a thing is safe to be deleted, it eventually will be.
B() and C() will be deleted if A stops pointing to them and A was the only thing pointing to them in the first place.
If you set it to null, then yes it is a signal to the GC to deallocate the memory when it needs the memory. But this will only happen if there are no more instances referencing that object.
If there are still instances referencing an object, it will not be GC-ed until there are completely NO instances referencing that object. So B() and C() will be GC-ed only if A() was the only one referencing them.
This effect can be easily observed by using Java to read a huge text file (about 3mb) with a Scanner, then closing and discarding the Scanner, and invoking System.gc() when you are done.
If you nullify all the references to A and if there are no other live references to B and C then those will be GCed too when the GC runs.
Invoking System.gc() does not guarantee that gc will run instantly. It may or may not run, there is no guarantee at all.
And There is no guaranteed way to force gc run immediately as you request it.
Yes, you can see the effect as gc runs freeing memory.
to see visual graphs/info ... about heap/memory usage, you can use jdk tools, find it for windows at:
JAVA_HOME\bin\jconsole.exe
Its a thumb of rule, that when an object has NO reference attached to it, its a toast for the Garbage collector to eat.
Marking A null will, make A a toast for the GC. If the reference pointing to A, was the only reference to B and C, then both of these are too the candidate for being Garbage Collected
finalize is the object class method, that is called when an object is Garbage Collected.

In Java, can you link the garbage collection between two classes?

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).

Categories

Resources