线程作为GC根节点

10

我有一个关于GC根的问题。我看到其中一个GC根是“活动线程”。这是什么意思?

我一直以为每个线程都有自己的堆栈,堆栈中的局部变量是线程的GC根,现在我感到困惑了。除了框架堆栈或本地堆栈上没有的对象引用之外,线程表示还有哪些其他类型的对象引用?

另一个问题是年轻代回收是否使用GC根,还是只用于主要的算法?

谢谢

更新: 好的,抱歉,为了简单起见:我读了这篇短文:yourkit.com/docs/java/help/gc_roots.jsp,并且有一个“Thread”选项作为GC根,这意味着什么,线程是一个GC根? Thread GC根引用哪些类型的对象,这些对象不是由其堆栈引用的?为什么这两个类别不同?


1
你的问题有些令人困惑。1)当然,只有活动线程才算作GC根。2)什么是“线程表示”?3)静态变量是非堆栈GC根。4)每种GC变体都考虑了GC根;不考虑它们是不可能的。 - Marko Topolnik
好的,抱歉,为了简单起见:我读了这篇短文:http://www.yourkit.com/docs/java/help/gc_roots.jsp,并且有一个“线程”选项作为GC根,那么线程作为GC根到底意味着什么?线程GC根引用哪些对象,而这些对象不是由它的堆栈引用的?为什么这两个类别是不同的? - alobodzk
@MarkoTopolnik 我认为静态变量不是根,否则类加载器将永远无法卸载。 - Peter Lawrey
@alobodzk 最好将您的评论编辑到问题中,因为它是关键信息。 - Marko Topolnik
2
我的猜测是:与活动线程对应的Thread实例是一个GC根,即使在堆栈或静态变量中没有对它的引用。 - Marko Topolnik
3个回答

6
我看到GC根之一是“Live thread”,这是什么意思?
一个“live thread”是已经启动但尚未终止的线程。
除了帧堆栈或本地堆栈上没有的对象引用之外,线程表示还有哪些类型的对象引用呢?
没有。
当他们说(活)线程是GC根时,他们实际上指的是线程堆栈框架中所有值的总和。
(“frame stack”和“native stack”在不同的执行模式下具有基本相同的信息;即解释与编译。理解GC根时,没有必要区分它们。)
那么线程是GC根究竟是什么意思呢?
这意味着线程的堆栈是GC根,所有线程堆栈框架中所有活变量的内容都是可达的。
这些东西实际上是在说同样的事情。
另一个问题是年轻代收集是否使用GC根,还是只用于主要算法?
(首先应注意的是,并非所有Java GC都是分代的,而且我们所做的任何概括都可能被新的GC技术所推翻。)
年轻代收集肯定会使用。为了避免删除由这些根引用的对象,需要知道所有根中的内容。由于GC根可以引用年轻代中的对象,因此年轻代收集器需要使用它们。
从某种意义上说,所有的收集器都会使用它们。但从另一个角度来看,在一些“停止世界”收集阶段之间直接使用GC根。对于那些在正常线程运行时运行的收集器/阶段,用户线程可能会修改GC根。GC基础设施使用诸如写屏障之类的东西来捕获可能影响到可达性的任何更改...以各种方式。

感谢澄清! - alobodzk
我怀疑YourKit的分类是随意的。他们肯定用这些区别来表达某种含义。 - Marko Topolnik
框架堆栈用于解释代码,本地堆栈由解释器本身和JIT编译的代码使用。 - Marko Topolnik
@MarkoTopolnik - 如果您查看此帖子链接到的页面,它根本没有提到“本地堆栈”。分类不是您的工具。 - Stephen C
也许有一些误解...我所指的区别是在YourKit中“Live Thread”的单独类别。关于堆栈的评论与此无关(OP提到了这两个)。YourKit没有区分这两者,我认为要区分它们可能会相当困难。 - Marko Topolnik
@MarkoTopolnik - 说实话,我认为OP只是纯粹的困惑了,因为他试图从使用不同术语的GC的不同描述中提取含义。显然,他引用的主要来源YourKit文档并没有提到“本地堆栈”。我认为对他最好的建议是不要尝试将他的来源组合在一起。 - Stephen C

0

想象一种使用Java线程对象本地新建的方法,当该方法退出时,该对象就消失了(引用超出范围并且任何堆分配的内存都符合GC条件)。如果在同一个方法中启动线程,则该线程对象及其引用的任何内容的生命周期也与活动/运行线程的生命周期相关联。直到线程退出,从运行线程仍然引用的任何内存都不符合GC条件,并且该线程被称为GC根。

线程可以通过堆栈或堆两种不同方式分配内存。堆栈存储不会进行GC,但会在当前堆栈帧取消时回收。通常在代码中使用“new”时分配堆存储(请注意,“new”并不总是意味着堆存储,请参见逃逸分析)。堆会进行GC。

学习更多关于GC根的好方法是对正在运行的Java应用程序进行堆转储,并将其加载到Visual VM或Eclipse MAT中,从那里您应该能够检查GC根。

年轻代集合将使用GC根,因为具有GC根的对象不符合GC条件,但最好以给定算法的术语来谈论。


0
JVM将其线程分为几个部分,一些专门用于垃圾回收,一些用于其他内部JVM任务,还有一些执行用户提供的可执行文件的部分。
在这种情况下,“可达”是指用户执行线程可以访问的。这包括第一个线程,它被绑定到从public static void main(String[] args)运行的线程以及从该线程启动的所有线程,减去不可达或完成的线程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接