Java 中的线程何时从内存中删除?

When thread in Java is removed from memory?

来自 Java API 文档:

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.

我希望我的假设是正确的,一旦线程完成其 run() 方法,它就可以进行垃圾回收。在同样的情况下,我只是想知道:

  1. 如果在 returning 后它不符合垃圾收集条件 来自 run(),是否应该将其引用设置为 null 来做到这一点?
  2. 符合垃圾回收条件并不一定意味着 该对象将从内存中删除。这是在全权酌情决定 垃圾收集时的底层操作系统/JVM。 但是如何确保(通过 Java 程序或外部工具)该对象已完全从 内存?
  3. 如果一个线程一旦完成它的 运行() 方法就被认为是死的,为什么 我还能执行 isAlive()getState() 在 同一个线程对象? return falseRUNNABLE 这两个调用 分别。

线程已完成执行的事实不会改变对象引用的有效性。当您持有该引用时,Thread 对象不能被垃圾回收。

这意味着当您持有对线程的引用时,您可以调用 isAlive 之类的东西。当您释放所有引用时,线程可以被垃圾回收。

如果您希望在不阻止该对象被垃圾回收的情况下引用一个对象,那么您必须使用 a WeakReference。当您使用这样的引用时,您必须检查引用的对象是否仍然存在。

我认为垃圾收集器会在内存中没有对象引用时收集对象。在线程的情况下,进程是 运行,因此垃圾收集器不会收集线程对象。

每一棵对象树必须有一个或多个根对象。只要应用程序可以到达这些根,就可以通过

访问整棵树
javabook.compuware.com/content/memory/how-garbage-collection-works.aspx

看来您正陷入 Java 中不理解线程的常见陷阱:线程本身不是 Java 对象。它是本机资源(执行线程)。一旦完成 运行 它的代码,它就会 "removed from memory"。

另一方面,Thread 的实例只是一个普通的 Java 对象,与任何其他对象具有相同的生命周期——除了额外的规则,它至少保持可达只要底层本机线程还活着。您可以随时调用 Thread.currentThread().

这一事实暗示了这一点

因此,如果您保留对负责死线程的 Thread 实例的引用,它不会神奇地消失,它的所有方法将继续按指定运行。你想坚持多久就坚持多久。

关于您的问题 2,"removing"内存中的对象实际上是一个毫无意义的术语。运行时本身实际上并不知道收集的对象——它们是它忘记的对象。

Thread class 是本机内存中真实线程的代理。

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

其实在运行()之后还有一段代码,这段代码处理未捕获的异常。

一旦线程死亡,其本机内存和堆栈将立即释放,无需 GC。然而,Thread 对象就像任何其他对象一样,它一直存在,直到 GC 决定它可以被释放,例如没有强引用。

同样,FileOutputStream 是操作系统中文件的代理。即使文件已被 close() 甚至删除,您仍然可以引用该对象。

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

您很少需要在任何地方执行此操作。事实上,首先不保留对线程的引用,或者使用 ExecutorService 来管理线程通常更简单。

当我有一个具有 Thread 字段的对象时,我通常会在线程终止时让该对象终止,因此不需要 null 删除该字段。

我还使用了用于 Fork/Join 的内置线程池。这是一种在后台线程中执行任务的更轻量级方法,因为它不会创建和销毁太多线程。

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?

你不能也不应该尝试。 GC会在需要的时候清理资源。

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. 在 运行 之前和期间,线程对象本身是 GC 根,也就是说:它们和任何可以从它们强烈访问的对象都不能被收集。
  2. 线程完成后 运行,它 "reverts" 成为普通对象。与任何其他对象相同的 GC 规则适用于它们。因此,例如,虽然您对它们有很强的引用,但它们不会被收集,是的,您可以毫无问题地调用它们的方法。

所以我的建议是像对待 ListMap 类型的对象一样对待 "dead" 线程。适用于它们的内容适用于完成 运行.

的线程

如果在从 运行() returning 后它没有资格进行垃圾收集,是否应该将其引用设置为 null 来做到这一点?

显式 将对象设置为 null(如果您确定它们将来不会被使用)总是更好,以使 GC 的工作更容易一些。

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 --> 如果调用 gc 时线程是 运行ning

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

case :2 --> IF 调用 gc 时线程已 完成 运行ning

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

符合垃圾回收条件并不一定意味着该对象将从内存中删除。垃圾收集时由底层操作系统/JVM 自行决定。但是如何确保(通过 Java 程序或外部工具)该对象已从内存中完全删除?

在Java中,你只能说什么时候object变成了unreachable(不是GCed,无法访问.)。 finalize() 将在您的 onjecy 变得 unreachable 时被调用。

如果一个线程一旦完成它的 运行() 方法就被说死了,为什么我仍然能够在同一个线程上执行 isAlive() 或 getState()目的?这两个调用分别为 return false 和 RUNNABLE。 - 线程可能已完成执行。但它仍将处于一种状态。 终止 状态。您正在线程实例上调用这些方法。所以,它仍然保存着一些状态数据。