Java 线程和垃圾回收器

2022-09-01 20:26:12

可能的重复:
是否收集了 Java 线程垃圾

请考虑以下类:

class Foo implements Runnable {

  public Foo () {
       Thread th = new Thread (this);
       th.start();
  }

  public run() {
    ... // long task
  }

}

如果我们通过Foo

new Foo();
new Foo();
new Foo();
new Foo();

(请注意,我们不会保留指向它们的指针)。

  1. 垃圾回收器是否可以在线程结束之前删除这些实例?(换句话说:有没有对对象的引用?run()Foo

  2. 另一方面,在'run()'中的线程结束后,这些实例是否会被GC删除,或者我们是否浪费了内存(“内存泄漏”)?

  3. 如果任一 1.或 2.是一个问题,正确的方法是什么?

谢谢


答案 1
  1. 活动线程引用的任何对象都不能取消分配。
  2. 是的,在'run()'中的线程结束后,GC将删除实例。
  3. 无概率。

答案 2
  1. 这些实例是否可以在 run() 中的线程结束之前由垃圾回收器删除?(换句话说:有没有提到Foo对象?

不。当构造函数运行时,GC 不会收集对象。否则,即使是最简单的:

Customer c = new Customer();

在 构造函数正在运行时可能会失败。另一方面,当您启动新线程时,线程对象将成为新的 GC 根目录,因此该对象引用的所有内容都不是垃圾回收的对象。Customer

  1. 另一方面,在'run()'中的线程结束后,这些实例是否会被GC删除,或者我们是否浪费了内存(“内存泄漏”)?

线程完成后,它不再是 GC 根。如果没有其他代码指向该线程对象,则将对其进行垃圾回收。

  1. 如果任一 1.或 2.是一个问题,正确的方法是什么?

你的代码很好。然而:

  • 从单元测试的角度来看,在构造函数中启动新线程是一个糟糕的主意

  • 保留对所有正在运行的线程的引用可能是有益的,例如,如果您以后要中断这些线程。