【问题标题】:Thread as a GC root线程作为 GC 根
【发布时间】:2014-10-07 09:24:23
【问题描述】:

我有一个关于 GC 根的问题。我读到 GC 的根源之一是“实时线程”。这意味着什么?

我一直觉得每个线程都有自己的堆栈,堆栈的局部变量是线程的 GC 根,现在我很困惑。线程表示还有哪些其他类型的对象引用,它们不在帧堆栈或本机堆栈上?

另一个问题是年轻代收集是使用 GC 根,还是仅用于主要算法?

谢谢

更新: 好的,抱歉,为了简单起见:我已经阅读了这篇简短的文章:yourkit.com/docs/java/help/gc_roots.jsp,并且有一个“线程”选项作为 GC 根,这究竟意味着线程是GC 根?什么样的对象被 Thread GC root 引用,而不被它的栈引用?为什么这两个类别不同?

【问题讨论】:

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

标签: java multithreading garbage-collection gc-roots


【解决方案1】:

我读到 GC 根之一是“实时线程”。这是什么意思?

活动线程是已启动但尚未终止的线程。

线程表示还有哪些其他类型的对象引用,它们不在帧堆栈或本机堆栈上?

无。

当他们说(活动)线程是 GC 根时,他们的意思是(实际上)所有线程堆栈帧中的值。

(“帧堆栈”和“本机堆栈”在不同的执行模式下持有基本相同的信息;即解释与编译。在理解 GC 根时无需区分它们。)

...这究竟意味着线程是 GC 根?

表示线程的栈是一个GC根,所有线程的栈帧中所有活变量的内容都是可达的。

这些东西实际上都在说同一件事


另一个问题是年轻代收集是使用 GC 根,还是仅用于主要算法?

(首先应该注意,并非所有 Java GC 都是分代的,我们所做的任何概括都可能被新的 GC 技术呈现为错误的。)

年轻代集合当然可以。它需要知道所有根中的内容,以避免删除这些根引用的对象。由于 GC 根可以引用年轻代中的对象,因此年轻代收集器需要使用它们。

从某种意义上说,所有收藏家都使用它们。但在另一种意义上,GC 根仅在某些“停止世界”收集阶段直接使用。对于那些在正常线程运行时运行的收集器/阶段,用户线程可以修改 GC 根。 GC 基础架构使用诸如写屏障之类的东西来捕获可能影响可达性的任何更改......以各种方式。

【讨论】:

  • 感谢您的澄清!
  • 我怀疑 yourkit 的分类是任意的。它们肯定意味着具有这些区别的某些东西
  • 帧堆栈用于解释代码,本地堆栈由解释器本身和 JIT 编译代码使用。
  • @MarkoTopolnik - 如果您查看这篇文章链接到的页面,它根本没有提到“本机堆栈”。分类不是 yourkit 的......
  • 可能是一个误解......我想到的区别是 YourKit 中“Live Thread”的单独类别。对堆栈的评论与此无关(OP 提到了这两个)。 YourKit 无法区分这两者,我想很难区分它们。
【解决方案2】:

想象一个带有 java 线程对象 local new'ed 的方法,当方法退出时,对象就消失了(引用超出范围并且任何堆分配的内存都符合 GC 条件)。如果以相同的方法启动线程,那么现在该线程对象及其引用的任何内容的生存时间也与实时运行线程的生存时间相关联。在线程退出之前,仍然从正在运行的线程引用的任何内存都没有资格进行 GC,并且该线程被称为 GC 根。

线程可以通过堆栈或堆以两种不同的方式分配内存。堆栈存储不是 GC,而是在当前堆栈帧展开时回收。当您在代码中使用“new”时,通常会分配堆存储(注意 new 并不总是意味着堆存储,请参阅 Escape Analysis)。堆是 GC'ed。

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

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

【讨论】:

    【解决方案3】:

    JVM 对其线程进行分区,一些专门用于垃圾收集,一些用于其他内部 JVM 任务,还有一些执行用户提供的可执行文件部分。

    在这种情况下,可达意味着用户执行线程可达。这包括第一个从public static void main(String[] args) 运行的线程以及从该线程启动的所有线程,减去那些变得无法访问或完成的线程。

    【讨论】:

      猜你喜欢
      • 2023-04-06
      • 2023-03-03
      • 2015-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多