ChatGPT解决这个技术问题 Extra ChatGPT

When is the finalize() method called in Java?

I need to know when the finalize() method is called in the JVM. I created a test class which writes into a file when the finalize() method is called by overriding it. It is not executed. Can anybody tell me the reason why it is not executing?

Just as a side note: finalize is marked as deprecated in Java 9
if anything has a reference to your object or even the class. finalize() and garbage collection doesn't have any impact.
It's deprecated starting Java9. docs.oracle.com/javase/9/docs/api/java/lang/…
As of openjdk.java.net/jeps/421 (Java 18) finalizers are not removed yet.

J
Joachim Sauer

The finalize method is called when an object is about to get garbage collected. That can be at any time after it has become eligible for garbage collection.

Note that it's entirely possible that an object never gets garbage collected (and thus finalize is never called). This can happen when the object never becomes eligible for gc (because it's reachable through the entire lifetime of the JVM) or when no garbage collection actually runs between the time the object become eligible and the time the JVM stops running (this often occurs with simple test programs).

There are ways to tell the JVM to run finalize on objects that it wasn't called on yet, but using them isn't a good idea either (the guarantees of that method aren't very strong either).

If you rely on finalize for the correct operation of your application, then you're doing something wrong. finalize should only be used for cleanup of (usually non-Java) resources. And that's exactly because the JVM doesn't guarantee that finalize is ever called on any object.


@Rajesh. No. It's not a "life span" issue. You can put your program in an infinite loop (for years), and if the garbage collector is not needed it will never run.
@VikasVerma: the perfect replacement is nothing: you should not need them. The only case where it would make sense is if your class manages some external resource (like a TCP/IP connection, file ... anything that the Java GC can't handle). In those cases the Closable interface (and the idea behind it) is probably what you want: make .close() close/discard the resource and require the user of your class to call it at the right time. You might want to add a finalize method "just to be save", but that would be more of a debugging tool than an actual fix (because it's not reliable enough).
@Dragonborn: that's actually a quite different question and should be asked separately. There are shutdown hooks, but they are not guaranteed if the JVM shuts down unexpectedly (a.k.a. crashes). But their guarantees are significantly stronger than those for finalizers (and they are safer as well).
Your last paragraph says to use it only for cleaning up resources even though there is no guarantee it will ever be called. Is this optimism speaking? I would assume that something unreliable as this wouldn't be suited for cleaning up resources either.
Finalizers can sometimes save the day... I had a case where a 3rd party library was using a FileInputStream, never closing it. My code was calling the library's code, and then tried to move the file, failing because it was still open. I had to force call System.gc() to invoke FileInputStream::finalize(), then I could move the file.
P
Paul Bellora

In general it's best not to rely on finalize() to do any cleaning up etc.

According to the Javadoc (which it would be worth reading), it is:

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.

As Joachim pointed out, this may never happen in the life of a program if the object is always accessible.

Also, the garbage collector is not guaranteed to run at any specific time. In general, what I'm trying to say is finalize() is probably not the best method to use in general unless there's something specific you need it for.


On other words (just to clarify for future readers) it is never called on the main class, as, when the main class closes, no garbage needs to be collected. The OS cleans up everything the app used anyway.
"not the best method to use... unless there's something specific you need it for" - uh, that sentence applies to 100% of everything, so isn't helpful. Joachim Sauer's answer is much better
@Zom-B your example is helpful for clarification, but just to be pedantic, presumably it could be called on the main class if the main class creates a non-daemon thread and then returns?
So what are the situations where finalize would be useful?
@MarkJeronimus - Actually, that is irrelevant. The finalize() method on for the main class is invoked when an >>instance<< of the class is garbage collected, not when the main method terminates. And besides, the main class could be garbage collected before the application finishes; e.g. in a multi-threaded app where the "main" thread creates other threads and then returns. (In practice, a non-standard classloader would be required ....)
X
XpiritO

protected void finalize() throws Throwable {} every class inherits the finalize() method from java.lang.Object the method is called by the garbage collector when it determines no more references to the object exist the Object finalize method performs no actions but it may be overridden by any class normally it should be overridden to clean-up non-Java resources ie closing a file if overridding finalize() it is good programming practice to use a try-catch-finally statement and to always call super.finalize(). This is a safety measure to ensure you do not inadvertently miss closing a resource used by the objects calling class protected void finalize() throws Throwable { try { close(); // close open files } finally { super.finalize(); } } any exception thrown by finalize() during garbage collection halts the finalization but is otherwise ignored finalize() is never run more than once on any object

quoted from: http://www.janeg.ca/scjp/gc/finalize.html

You could also check this article:

Object finalization and cleanup


The JavaWorld article you link to is from 1998, and has some interesting advice, particularly the suggestion that one call System.runFinalizersOnExit() to ensure finalizers run before the JVM exits. That method is currently deprecated, with the comment 'This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.' So I will not be doing that.
Since runFinalizerOnExit() is NOT thread-safe, what one could do is Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { destroyMyEnclosingClass(); } }); in the constructor of the Class.
@Ustaman Sangat That's a way to do it, but remember this sets a reference to your instance from the shutdownHook, which pretty much guarantees that your class is never garbage collected. In other words, it's a memory leak.
@pieroxy, while I agree everyone else here regarding not to use finalize() for anything, I don't see why there would have to be a reference from the shutdown hook. One could have a soft reference.
r
rsp

The Java finalize() method is not a destructor and should not be used to handle logic that your application depends on. The Java spec states there is no guarantee that the finalize method is called at all during the livetime of the application.

What you problably want is a combination of finally and a cleanup method, as in:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {
    if (null != myObj) {
        myObj.cleanup();
    }
}

This will correctly handle the situation when the MyClass() constructor throws an exception.


@Anatoly the edit is wrong, it misses the situation where the MyClass() constructor throws the exception. This will trigger a NPE in the new version of the example.
r
rmtheis

Check out Effective Java, 2nd edition page 27. Item 7: Avoid finalizers

Finalizers are unpredictable, often dangerous, and generally unnecessary. never do anything time-critical in a finalizer. never depend on a finalizer to update critical persistent state.

To terminate a resource, use try-finally instead:

// try-finally block guarantees execution of termination method Foo foo = new Foo(...); try { // Do what must be done with foo ... } finally { foo.terminate(); // Explicit termination method }


or use try-with-resources
This assumes an object's lifetime is in the scope of one function. Which, of course, is not the case that the OP is referring to, nor is it the case basically anyone needs. Think "cache engine return value reference count". You want to free the cache entry when the last ref is freed, but you don't know when the last ref is freed. finalize() can decrement a ref count, for example... but if you require your users to explicitly call a free function, you're asking for memory leaks. usually i just do both (release function + double check in finalize ...) ...
S
Stephen C

When is the finalize() method called in Java?

The finalize method will be called after the GC detects that the object is no longer reachable, and before it actually reclaims the memory used by the object.

If an object never becomes unreachable, finalize() will never be called on it.

If the GC doesn't run then finalize() may never be called. (Normally, the GC only runs when the JVM decides that there is likely to enough garbage to make it worthwhile.)

It may take more than one GC cycle before the GC determines that a specific object is unreachable. (Java GCs are typically "generational" collectors ...)

Once the GC detects an object is unreachable and finalizable, it is places on a finalization queue. Finalization typically occurs asynchronously with the normal GC.

(The JVM spec actually allows a JVM to never run finalizers ... provided that it doesn't reclaim the space used by the objects. A JVM that was implemented this way would be crippled / useless, but it this behavior is "allowed".)

The upshot is that it is unwise to rely on finalization to do things that have to be done in a definite time-frame. It is "best practice" not to use them at all. There should be a better (i.e. more reliable) way to do whatever it is you are trying to do in the finalize() method.

The only legitimate use for finalization is to clean up resources associated with objects that have been lost by application code. Even then, you should try to write the application code so that it doesn't lose the objects in the first place. (For example, use Java 7+ try-with-resources to ensure that close() is always called ...)

I created a test class which writes into a file when the finalize() method is called by overriding it. It is not executed. Can anybody tell me the reason why it is not executing?

It is hard to say, but there are a few possibilities:

The object is not garbage collected because it is still reachable.

The object is not garbage collected because the GC doesn't run before your test finishes.

The object is found by the GC and placed in the finalization queue by the GC, but finalization isn't completed before your test finishes.


c
cst1992

Since there is an uncertainity in calling of finalize() method by JVM (not sure whether finalize() which is overridden would be executed or not), for study purposes the better way to observe what happens when finalize() is called, is to force the JVM to call garbage collection by command System.gc().

Specifically, finalize() is called when an object is no longer in use. But when we try to call it by creating new objects there is no certainty of its call. So for certainty we create a null object c which obviously has no future use, hence we see the object c's finalize call.

Example

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

Output

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

Note - Even after printing upto 70 and after which object b is not being used in the program, there is uncertainty that b is cleared or not by JVM since "Called finalize method in class Bike..." is not printed.


Calling System.gc(); is not a guarantee that the garbage collection will actually be run.
It is also not guaranteed what kind of collection will be run. Relevant since most Java GCs are "generational" collectors.
O
OnaBai

finalize will print out the count for class creation.

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

main

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

As you can see. The following out put show the gc got executed first time when the class count is 36.

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F

M
Martin Kersten

Having wrestled with finalizer methods lately (in order to dispose connection pools during testing), I have to say that finalizer lacks many things. Using VisualVM to observe as well as using weak references to track the actual interaction I found that following things are true in a Java 8 environment (Oracle JDK, Ubuntu 15):

Finalize is not called immediately the Finalizer (GC part) individually owns the reference elusively

The default Garbage Collector pools unreachable objects

Finalize is called in bulk pointing to an implementation detail that there is a certain phase the garbage collector frees the resources.

Calling System.gc() often does not result in objects being finalized more often, it just results in the Finalizer getting aware of an unreachable object more rapidly

Creating a thread dump almost always result in triggering the finalizer due to high heap overhead during performing the heap dump or some other internal mechanism

Finalization seams to be bound by either memory requirements (free up more memory) or by the list of objects being marked for finalization growing of a certain internal limit. So if you have a lot of objects getting finalized the finalization phase will be triggered more often and earlier when compared with only a few

There were circumstances a System.gc() triggered a finalize directly but only if the reference was a local and short living. This might be generation related.

Final Thought

Finalize method is unreliable but can be used for one thing only. You can ensure that an object was closed or disposed before it was garbage collected making it possible to implement a fail safe if objects with a more complex life-cylce involving a end-of-life action are handled correctly. That is the one reason I can think of that makes it worth in order to override it.


D
Darin Kolev

An Object becomes eligible for Garbage collection or GC if its not reachable from any live threads or any static refrences in other words you can say that an object becomes eligible for garbage collection if its all references are null. Cyclic dependencies are not counted as reference so if Object A has reference of object B and object B has reference of Object A and they don't have any other live reference then both Objects A and B will be eligible for Garbage collection. Generally an object becomes eligible for garbage collection in Java on following cases:

All references of that object explicitly set to null e.g. object = null Object is created inside a block and reference goes out scope once control exit that block. Parent object set to null, if an object holds reference of another object and when you set container object's reference null, child or contained object automatically becomes eligible for garbage collection. If an object has only live references via WeakHashMap it will be eligible for garbage collection.


If a final field of an object is used repeatedly during a slow computation, and the object will never be used after that, would the object be kept alive until the last the the source code requests the field, or could the JIT copy the field to a temporary variable and then abandon the object before computation?
@supercat: an optimizer may rewrite code to a form where the object is not created in the first place; in that case, it may get finalized right after its constructor finished, unless synchronization forces an ordering between the object’s use and the finalizer.
@Holger: In cases where the JIT can see everything that's ever going to happen to an object between its creation and abandonment, I don't see any reason for the JIT to fire the finalizer early. The real question would be what code needs to do to ensure that the finalizer can't fire within a particular method. In .NET there is a GC.KeepAlive() function which does nothing except force the GC to assume that it might use an object, but I know of no such function in Java. One could use volatile variable for that purpose, but using a variable solely for such a purpose would seem wasteful.
@supercat: The JIT doesn’t fire finalization, it just arranges the code to not keep a reference, though, it might be beneficial to directly enqueue the FinalizerReference, so that it doesn’t need a GC cycle to find out that there are no references. Synchronization is sufficient to ensure a happens-before relationship; since the finalization may (actually is) running in a different thread, it often is formally necessary anyway. Java 9 is going to add Reference.reachabilityFence
@Holger: If the JIT optimizes out object creation, the only Finalize would get called at all would be if the JIT produced code that did so directly. Would synchronization code typically be expected for objects which only expect to be used in a single thread? If an object performs some action that needs to be undone before it's abandoned (e.g. opening a socket connection and acquiring exclusive use to the resource on the other end), having a finalizer close the connection while code is still using the socket would be a disaster. Would it be normal for code to use synchronization...
C
Craig S. Anderson

finalize method is not guaranteed.This method is called when the object becomes eligible for GC. There are many situations where the objects may not be garbage collected.


Incorrect. What you are saying is that an object is finalized when it becomes unreachable. It is actually called when the method is actually collected.
A
Amarildo

Sometimes when it is destroyed, an object must make an action. For example, if an object has a non-java resource such as a file handle or a font, you can verify that these resources are released before destroying an object. To manage such situations, java offers a mechanism called "finalizing". By finalizing it, you can define specific actions that occur when an object is about to be removed from the garbage collector. To add a finalizer to a class simply define the finalize() method. Java execution time calls this method whenever it is about to delete an object of that class. Within the finalize method() you specify actions to be performed before destroying an object. The garbage collector is periodically searched for objects that no longer refer to any running state or indirectly any other object with reference. Before an asset is released, the Java runtime calls the finalize() method on the object. The finalize() method has the following general form:

protected void finalize(){
    // This is where the finalization code is entered
}

With the protected keyword, access to finalize() by code outside its class is prevented. It is important to understand that finalize() is called just just before the garbage collection. It is not called when an object leaves the scope, for example. It means you can not know when, or if, finalize() will be executed. As a result, the program must provide other means to free system resources or other resources used by the object. You should not rely on finalize() for normal running of the program.


M
Meet Doshi

Class where we override finalize method

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

The chances of finalize method being called

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

when the memory is overloaded with dump objects the gc will call finalize method

run and see the console, where you dont find the finalize method being called frequently, when the memory is getting overloaded then the finalize method will be called.


F
Fourat

finalize() is called just before garbage collection. It is not called when an object goes out of scope. This means that you cannot know when or even if finalize() will be executed.

Example:

If your program end before garbage collector occur, then finalize() will not execute. Therefore, it should be used as backup procedure to ensure the proper handling of other resources, or for special use applications, not as the means that your program uses in its normal operation.


J
JavaDev

Java allows objects to implement a method called finalize() that might get called. finalize() method gets called if the garbage collector tries to collect the object. If the garbage collector doesn't run, the method doesn't get called. If the garbage collector fails to collect the object and tries to run it again, the method doesn't get called in the second time. In practice, you are highly unlikely to use it in real projects. Just keep in mind that it might not get called and that it definitely won't be called twice. The finalize() method could run zero or one time. In the following code, finalize() method produces no output when we run it since the program exits before there is any need to run the garbage collector.

Source


U
Utkarsh

As pointed out in https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers,

There is no fixed time at which finalizers must be executed because time of execution depends on the Java Virtual Machine (JVM). The only guarantee is that any finalizer method that executes will do so sometime after the associated object has become unreachable (detected during the first cycle of garbage collection) and sometime before the garbage collector reclaims the associated object's storage (during the garbage collector's second cycle). Execution of an object's finalizer may be delayed for an arbitrarily long time after the object becomes unreachable. Consequently, invoking time-critical functionality such as closing file handles in an object's finalize() method is problematic.


P
Panagiotis Bougioukos

Recent news from JDK 18

According to JEPS 421 delivered on openjdk 18 the finalization and therefore the functionality of finalize() method will be marked as deprecated(forRemoval=true) meaning the permanent removal would follow in some later version after jdk 18.

As from jdk 18 a new command-line option --finalization=disabled disables finalization mechanism everywhere even for declarations inside the jdk itself.

This is also relevant to this question here as the reason it is planned for removal, is some major flaws it contains. One of those flaws is that a very long time may pass between the moment an object becomes unreachable and the moment its finalizer is called. It is also true that the GC provides no guarantee that any finalizer will ever be called.


F
Fruchtzwerg

Try runiing this Program for better understanding

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}