Java线程和垃圾收集器
可能重复:
是否收集了Java Thread Garbage
考虑以下课程:
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();
(请注意,我们没有指向它们的指针)。
-
在
run()
的线程结束之前 ,垃圾收集器是否可以删除这些实例? (换句话说:是否有对Foo
对象的引用?) -
而且,另一方面,在`run()’中的线程结束后,或者我们是否在浪费内存(“内存泄漏”)后,GC会删除这些实例吗?
-
如果1.或2.是问题,那么正确的方法是什么?
谢谢
- 活动线程引用的任何对象都不能被解除分配。
- 是的,在`run()’中的线程结束后,GC将删除实例。
- 没问题。
- 在run()中的线程结束之前,垃圾收集器是否可以删除这些实例? (换句话说:是否有对Foo对象的引用?)
不。当构造函数运行时,GC不会收集对象。 否则即使是最简单的:
Customer c = new Customer();
在Customer
的构造函数运行时可能会失败。 另一方面,当您启动新线程时,线程对象将成为新的GC根 ,因此该对象引用的所有内容都不是垃圾回收的主题。
- 而且,另一方面,在`run()’中的线程结束后,或者我们是否在浪费内存(“内存泄漏”)后,GC会删除这些实例吗?
线程完成后,它不再是GC根目录。 如果没有其他代码指向该线程对象,则将对其进行垃圾回收。
- 如果1.或2.是问题,那么正确的方法是什么?
你的代码很好。 然而:
-
从unit testing的角度来看,在构造函数中开始一个新线程是一个糟糕的主意
-
保持对所有正在运行的线程的引用可能是有益的,例如,如果您想稍后中断这些线程。
在未指定线程组的情况下启动新线程会将其添加到默认组 :
如果group为null且存在安全管理器,则该组由安全管理器的getThreadGroup方法确定。 如果group为null且没有安全管理器,或者安全管理器的getThreadGroup方法返回null,则该组将设置为与创建新线程的线程相同的ThreadGroup。
只要它处于活动状态,该组将保留对该线程的引用,因此在此期间它不能进行GC。
当一个线程终止时(=当run()
因任何原因返回时),该线程将从线程组中删除。 这发生在从本机代码调用的私有方法exit()
中。 这是对线程的最后一次引用丢失并且符合GC条件的时间点。
请注意,代码表明ThreadGroup
可以为null
但情况并非如此。 各种空检仅仅是为了避免NPE在极少数情况下出现问题。 在Thread.init()
,如果Java无法确定线程组,您将获得NPE。
- 线程引用
Foo
对象。 线程在其运行期间始终被引用。 因此它不会被垃圾收集。 - 没有内存泄漏。 线程将结束并将在此过程中进行垃圾收集和
Foo
对象。 - 它应该工作正常。
假设您在run方法中创建对象,当run方法退出时,对象将超出范围,然后可用于垃圾回收。 运行只是另一种方法。 是否使用线程不会以任何方式更改垃圾回收行为。 您需要关心的是当对象超出范围时,通常与块范围(方法块,循环,块等)相关联。
因此,由于您没有开始对该对象的任何引用,您可能希望将创建该对象的逻辑提取到其自己的短期方法中。 这样,创建的对象不需要超出该方法的范围。