Is Object memory freed when we explicitly call fin

2019-02-27 05:10发布

问题:

This question already has an answer here:

  • Java and manually executing finalize 3 answers
  • When is the finalize() method called in Java? 16 answers

As far as my understanding goes finalize() and GC are two different aspects. GC uses finalize() method to free Object memory. We cannot state when GC will occur(even if we explicitly call System.gc()). But we can explicitly call finalize() on an Object.

Will the function be executed immediately(memory freed) or it waits till GC
occurs like System.gc() call?

Also as per the docs the finalize method is never invoked more than once by a Java virtual machine for any given object.

So what happens when we call finalize() first and GC happens at a later point of time.

If object memory is not freed on explicit call to object.finalize() then would't 
it being called again in the GC process violate the calling only once rule? 

回答1:

You have got it completely wrong.

Short answer: finalize() is a means to clean up resources (such as open files) just before the object is ready for garbage collection ( when no object has strong reference to it). It might/not be called. It is one step ahead of memory deallocation.

Long answer:

There is a separate daemon thread called as finalizer thread which is responsible for calling finalize() method . Finalization queue is the queue where objects which are ready to be called finalize() method are placed.

  1. When an Object is created, JVM checks if the user has overridden the finalize() method. If it has then it internally notes that this particular object has finalize() method.

When an object is ready for garbage collection, then the garbage collector thread checks if this particular object has finalize() from table mentioned in (1).

  • 2a) If it doesn’t then it is sent for garbage collection.

    2b) It is has, then it is added to the finalization queue. And it removes the entry of the object from the table (1).

Finalizer thread keeps polling the queue. For every object in the queue, its finalize() method is called. After calling the finalize() cycle from (2) is again repeated. If this object still has no strong reference, then sent for GC. If it has then ALWAYS (2a) is called because the entry was deleted in (2b)

Basically finalize() method is only called once.

So what’s the issue with the above cycle?

From (1). Its take extra time in object creation. Memory allocation in Java is 5x to 10x faster than malloc/calloc etc. All the time gained is lost in the procedure of noting the object in the table etc. I once tried it. Create 100000 objects in a loop and measure the time taken for program to terminate in 2 cases: One with no finalize(), Second with finalize(). Found it to be 20% faster.

From (2b): Memory Leakage and Starvation. If the object in the queue has references to a lot of memory resources, then all those objects wont get freed unless this object is ready for GC.If all the objects are heavy weight objects, then there can be a shortage.

From (2b): Because finalize() is called only once, what if in teh finalize() you had a strong reference to “this” object. Next time the object’s finalie() is never called hence can leave the object in an inconsistent state.

If inside finalize() an exception is thrown, it is ignored.

You do not know when finalize() is called as you have no control over when GC is called. Sometimes it might happen that you are printing the value’s in finalize() but the output is never shown, because your program might have got terminated by the time finalize() is called.

Hence avoid using it. Instead create a method say dispose() which will close the necessory resources or for final log etc.



回答2:

Answers are in Object.finalize API

1) GC calls finalize() so finalize() and GC are NOT two different aspects

2) You should not call finalize manually, but if you do it will not will not free any memory and it will not affect GC behaviour

3) It is said that it's guaranteed that GC will not call finalize twice, our calls do not count



回答3:

As per docs:

The finalize method is never invoked more than once by a Java virtual machine for any given object.

However, you cannot force GC to run, you can just kindly ask it via System.gc(). So best approach is putting resource-freeing code into finalize() method when overriding.