When thread in Java is removed from memory? [dupli

2020-06-04 05:55发布

问题:

From the Java API doc:

The Java Virtual Machine continues to execute threads until following occurs:

All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

I hope my assumption is correct that once thread finishes its run() method it becomes eligible for garbage collection. In the same context I am just curious to know about:

  1. If it doesn't become eligible for garbage collection after returning from run(), should one set its reference to null to do that?
  2. Being eligible for garbage collection doesn't necessarily mean that the object will be removed from memory. It is at the sole discretion of the underlying operating system / JVM when it is garbage collected. But how can one make sure (either through a Java program or external tool) that the object is completely removed from the memory?
  3. If a thread is said to be dead once it finishes its run() method, why can I still be able to execute isAlive() or getState() on the same thread object? Both the calls return false and RUNNABLE respectively.

回答1:

The Thread class is a proxy for the real thread which is in native memory.

I hope my assumption is correct that once thread finishes its run() method it becomes eligible for garbage collection.

There is actually a bit of code after run(), this code handles uncaught exceptions.

Once the thread dies its native memory and stack are freed immediately without needing a GC. However, the Thread object is like any other object and it lives until it is GC has decided it can be free e.g. there is no strong reference to it.

Similarly, a FileOutputStream is a proxy for a file in the operating system. You can still have a reference to the object even after the file has been close() or even deleted.

If it doesn't become eligible for garbage collection after returning from run(), should one set its reference to null to do that?

You rarely need to do this anywhere. In fact it is often simpler not keep a reference to the thread in the first place, or to use an ExecutorService to manage your threads.

When I have an object which has a Thread field I often have this object die when the thread dies, thus the field doesn't need to be nulled out.

I also use the built in thread pool used for Fork/Join. This is a more light weight way to perform tasks in a background thread as it doesn't create and destroy threads so much.

ExecutorService fjp = ForkJoinPool.commonPool();

Being eligible for garbage collection doesn't necessarily mean that the object will be removed from memory. It is at the sole discretion of the underlying operating system / JVM when it is garbage collected. But how can one make sure (either through a Java program or external tool) that the object is completely removed from the memory?

You can't and generally shouldn't try. The GC will clean up resources when it needs to.

If a thread is said to be dead once it finishes its run() method, why can I still be able to execute isAlive() or getState() on the same thread object? Both the calls return false and RUNNABLE respectively.

The thread object is like any other object. You can call methods on it for as long as you hold a reference to it.



回答2:

It seems that you are tripping on the common pitfall with unterstanding threads in Java: the thread itself is not a Java object. It is a native resource (thread of execution). It will be "removed from memory" as soon as it has finished running its code.

The instance of Thread, on the other hand, is just a plain Java object with the same lifecycle as any other object—except for the extra rule that it stays reachable at least as long as the underlying native thread is alive. This is implied by the fact that you can always call Thread.currentThread().

So, if you retain a reference to a Thread instance in charge of a dead thread, it will not magically disappear and all its methods will continue to operate as specified. You can hold on to it for as long as desired.

Regarding your question 2, "removing" an object from memory is a virtually meaningless term. The runtime itself has in fact no idea about the collected objects—they are those which it has forgot about.



回答3:

The fact that the thread has finished execution does not alter the validity of the reference to the object. While you hold that reference the Thread object cannot be garbage collected.

This means that while you hold a reference to the Thread you are able to call things like isAlive. When you release all references the Thread can be garbage collected.

If you wish to have a reference to an object without preventing that object from being garbage collected then you must use a a WeakReference. When you use such a reference you must check to see if the object referenced still exists.



回答4:

There are two things to consider about threads.

  1. Before and during running thread objects themselves are GC roots, that is: they and any objects strongly accessible from them can't be collected.
  2. Once a thread finishes running, it "reverts" to being an ordinary object. The same GC rules apply to them as to any other object. So for example while you have a strong reference to them, they won't be collected and yes, you can call methods on them without trouble.

So my advice is to treat "dead" threads like you would treat an object of type List or Map for example. What applies to them applies to threads that finished running.



回答5:

If it doesn't become eligible for garbage collection after returning from run(), should one set its reference to null to do that?

It is always better to explicitly set objects to null (if you are certain that they will not be used in the future) to make the GC's job little easier.

class Test {

protected void finalize() throws Throwable {
    System.out.println("test finalized");
};

public static void main(String[] args) {
    Thread t = new MyThread();
    t.start();
    Test test = new Test();

    try {
        System.out.println(t.getState());
        // t.join();
        t = null;
        test = null;
        // System.out.println(t.getState());

        Thread.sleep(500); // change this to say 2 or 3 sec i.e, until run() completes. The thread object will be finalized
        System.gc();
        System.out.println("gc call done..");
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

class MyThread extends Thread {

protected void finalize() throws Throwable {
    System.out.println("MyThread instance finalized..");
};

@Override
public void run() {
    for (int i = 0; i < 5; i++) {
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(i);

    }
}

}

O/P : case : 1 --> if thread is running when call to gc is made.

RUNNABLE
0
gc call done..
test finalized
1
2
3
4

case :2 --> IF thread has finished running when call to gc is made.

      RUNNABLE
    0
    gc call done..
    test finalized
    1
    2
    3
    4
MyThread instance finalized..

Being eligible for garbage collection doesn't necessarily mean that the object will be removed from memory. It is at the sole discretion of the underlying operating system / JVM when it is garbage collected. But how can one make sure (either through a Java program or external tool) that the object is completely removed from the memory?

In Java, you can only say when the object becomes unreachable (not GCed, unreachable.). finalize() will be called when your onjecy becomes unreachable.

If a thread is said to be dead once it finishes its run() method, why can I still be able to execute isAlive() or getState() on the same thread object? Both the calls return false and RUNNABLE respectively. - The thread might have finished its execution. But it will still be in a state. the terminated state. You are calling these methods on a thread instance. So, it still holds some state data.



回答6:

What I believe is garbage collector collects an object when there are no references of an object in the memory. In case of thread, the process is running so thread objects won't be collected by garbage collector.

Every object tree must have one or more root objects. As long as the application can reach those roots, the whole tree is reachable via

javabook.compuware.com/content/memory/how-garbage-collection-works.aspx