what will the Finalizer thread do if there is a infinite loop or deadlock in the Java finalize method
Asked Answered
A

3

16

what will the Finalizer thread do if there is a infinite loop or deadlock in the Java finalize method.

Azure answered 4/8, 2013 at 10:56 Comment(6)
Can you share with us any behavior you observed while trying this?Hallway
It is difficult to observe this, JVM doesn't even guarantee that finalize will be called, needles to say that you don't know when it is going to be calledDifferentiable
@Differentiable A simple println is enough. I have played with this a long while ago, finalize is getting called quite promptly. There are only rare cases when some unreachable objects do not get finalized until system shutdown.Hallway
@MarkoTopolnik it was in your case, but you can't tell if other implementations of the JVM will behave the sameDifferentiable
@morgano: If object is garbage collected finalize will be called: "The particular definition of finalize that can be invoked for an object is called the finalizer of that object. Before the storage for an object is reclaimed by the garbage collector, the Java Virtual Machine will invoke the finalizer of that object."Sivia
@Differentiable And you can't tell if it is difficult to observe this. Specfically, short-lived objects, which don't get tenured, are almost guaranteed to be finalized very soon.Hallway
C
17

The spec writes:

Before the storage for an object is reclaimed by the garbage collector, the Java Virtual Machine will invoke the finalizer of that object.

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.

I read this to mean that the finalizer must have completed before the storage may be reused.

The Java programming language does not specify which thread will invoke the finalizer for any given object.

It is important to note that many finalizer threads may be active (this is sometimes needed on large shared memory multiprocessors), and that if a large connected data structure becomes garbage, all of the finalize methods for every object in that data structure could be invoked at the same time, each finalizer invocation running in a different thread.

That is, finalization may occur in the garbage collector thread, in a separate thead, or even a separate thread pool.

A JVM is not permitted to simply abort executing a finalizer, and can only use a finite number of threads (threads are operating system resources, and operating systems don't support arbitrarily many threads). Non-terminating finalizers will therefore of necessity starve that thread pool, thereby inhibit collection of any finalizable objects, and cause a memory leak.

The following test program confirms this behavior:

public class Test {

    byte[] memoryHog = new byte[1024 * 1024];

    @Override
    protected void finalize() throws Throwable {
        System.out.println("Finalizing " + this + " in thread " + Thread.currentThread());
        for (;;);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            new Test();
        }
    }
}

On Oracle JDK 7, this prints:

Finalizing tools.Test@1f1fba0 in thread Thread[Finalizer,8,system]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at tools.Test.<init>(Test.java:5)
        at tools.Test.main(Test.java:15)
Cadal answered 4/8, 2013 at 11:24 Comment(4)
+1, Did more or less the same test, and got the same result. Only one finalizer thread is involved.Hallway
@mriton, what does the meaning of It is important to note that many finalizer threads may be active (this is sometimes needed on large shared memory multiprocessors). Does it have any connection with the GC algorithm we chose,such as CMS. And, is there a relationship between the number of Finalizer thread and the GC algorithm.Azure
A JVM may do this however it wants, and different JVMs may do it differently. If you are interested in a particular JVM, check its documentation (or more likely, its source code). lpiepiora's anwer appears to indicate that there is always a single finalizer thread in the Oracle JVM, irrespective of the garbage collection algorithm in use.Cadal
@meriton, so can i understand it like this, the finalizer thread just run the finalize method of unreachable objects, but the gc alrorithm are used for reclaimed the memory of the unreachable objects after the finalize method run.Azure
S
4

I would say that since the Java Specification doesn't tell how the finalize method must be invoked (just that it must be invoked, before the object is garbage collected), the behaviour is implementation specific.

The spec doesn't rule out having multiple threads running the process, but doesn't require it:

It is important to note that many finalizer threads may be active (this is sometimes needed on large shared memory multiprocessors), and that if a large connected data structure becomes garbage, all of the finalize methods for every object in that data structure could be invoked at the same time, each finalizer invocation running in a different thread.

Looking at the sources of the JDK7, the FinalizerThread keeps the queue of objects scheduled for finalization (actually objects are added to the queue by the GC, when proven to be unreachable - check ReferenceQueue doc):

private static class FinalizerThread extends Thread {
    private volatile boolean running;
    FinalizerThread(ThreadGroup g) {
        super(g, "Finalizer");
    }
    public void run() {
        if (running)
            return;
        running = true;
        for (;;) {
            try {
                Finalizer f = (Finalizer)queue.remove();
                f.runFinalizer();
            } catch (InterruptedException x) {
                continue;
            }
        }
    }
}

Each object is removed from the queue, and runFinalizer method is run on it. Check is done if the finalization had run on the object, and if not it is being invoked, as a call to a native method invokeFinalizeMethod. The method simply is calling the finalize method on the object:

JNIEXPORT void JNICALL
Java_java_lang_ref_Finalizer_invokeFinalizeMethod(JNIEnv *env, jclass clazz,
                                                  jobject ob)
{
    jclass cls;
    jmethodID mid;

    cls = (*env)->GetObjectClass(env, ob);
    if (cls == NULL) return;
    mid = (*env)->GetMethodID(env, cls, "finalize", "()V");
    if (mid == NULL) return;
    (*env)->CallVoidMethod(env, ob, mid);
}

This should lead to a situation, where the objects get queued in the list, while the FinalizerThread is blocked on the faulty object, which in turn should lead to OutOfMemoryError.

So to answer the original question:

what will the Finalizer thread do if there is a infinite loop or deadlock in the Java finalize method.

It will simply sit there and run that infinite loop until OutOfMemoryError.

public class FinalizeLoop {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                for (;;) {
                    new FinalizeLoop();
                }
            }
        };
        thread.setDaemon(true);
        thread.start();
        while (true);
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("Finalize called");
        while (true);

    }
}

Note the "Finalize called" if printed only once on the JDK6 and JDK7.

Sivia answered 4/8, 2013 at 11:36 Comment(2)
sorry, i do not agree with your example code above. the for loop will terminate at the same time as the main thread, so you may not see any thing.Azure
@Azure you're right, I've changed the code slightly to be sure that you'd see something eventually - I guess depending on when your GC kicks in. Thanks!Sivia
C
0

The objects will not be "freed", that is the memory will not be claimed back from them and also resources that are freed in the finalize method will remain reserved throughout.

Basically there is a queue holding all the objects waiting for their finalize() method to be executed. Finalizer thread picks up objects from this queue - runs finalize - and releases the object.

If this thread will be deadlocked the ReferenceQueue Queue will grow up and at some point OOM error will become inexorable. Also the resources will be hogged up by the objects in this queue. Hope this helps!!

for(;;)
{
  Finalizer f = java.lang.ref.Finalizer.ReferenceQueue.remove();
  f.get().finalize();
}
Cheree answered 10/4, 2014 at 11:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.