![]() |
1
136
Java的GC认为对象是“垃圾”,如果它们不能通过从垃圾收集根开始的链来访问,那么这些对象将被收集。即使对象可以相互指向以形成一个循环,但如果从根目录中切断它们,它们仍然是垃圾。 请参阅附录A中关于无法访问的对象的部分:中有关垃圾收集的真相 Java Platform Performance: Strategies and Tactics 为了血淋淋的细节。 |
![]() |
2
114
是的,Java垃圾收集器处理循环引用!
有一些称为垃圾收集根(gc根)的特殊对象。它们总是可以到达的,任何根上有它们的对象也是可以到达的。 一个简单的Java应用程序具有以下GC根:
为了确定哪些对象不再被使用,jvm会间歇性地运行非常恰当地称为 标记和扫描算法 . 它的工作原理如下
因此,如果无法从gc根访问任何对象(即使它是自引用或循环引用的),它将受到垃圾收集的影响。 当然,有时这可能会导致内存泄漏,如果程序员忘记去引用一个对象。
|
![]() |
3
11
垃圾收集器从一些始终被视为“可访问”的“根”位置集开始,例如CPU寄存器、堆栈和全局变量。它的工作原理是在这些区域中找到任何指针,并递归地找到它们指向的所有内容。一旦发现了所有这些, 一切 否则就是垃圾。 当然,有很多变化,主要是为了速度。例如,大多数现代垃圾收集器都是“分代的”,这意味着它们将对象划分为不同的代,当对象变老时,垃圾收集器在试图确定该对象是否仍然有效的时间之间会变得越来越长--它只是开始假设如果它活了很长一段时间,很有可能会继续活得更长。 尽管如此,基本的想法仍然是一样的:这一切都是基于从一些它认为理所当然的仍然可以使用的东西的根集合开始,然后追踪所有指针,以找到其他可以使用的东西。 有趣的是:垃圾收集器的这一部分与用于封送对象的代码(如远程过程调用)之间的相似程度常常让人感到惊讶。在每种情况下,您都从一些对象的根集合开始,并跟踪指针以查找所有其他引用的对象… |
![]() |
4
9
你是对的。您描述的垃圾收集的特定形式称为“ 参考计数 “。在最简单的情况下,它的工作方式(至少在概念上,大多数引用计数的现代实现实际上是完全不同的)如下所示:
这个简单的策略有一个你所描述的问题:如果a引用b和b引用a,那么它们的引用计数都可以 从未 小于1,这意味着它们永远不会被收集。 有四种方法可以解决这个问题:
顺便说一下,
其他
实现垃圾收集器的主要方法是
示踪
. 跟踪收集器基于
可达性
. 你从一些开始
根集
你知道的是
总是
可访问(例如,全局常量,或
由于循环只能在自身内访问,而不能从根集访问,因此将收集它。 |
![]() |
5
5
Java GCS并不像您描述的那样实际操作。更准确地说,它们从一组基本对象(通常称为“gc根”)开始,并将收集从根无法访问的任何对象。
因此,在您的例子中,一旦局部变量a、b和c在方法结束时超出范围,就没有更多的gc根直接或间接地包含对三个节点中任何一个的引用,它们将有资格进行垃圾收集。 如果你想的话,toubeer的链接有更多的细节。 |
![]() |
6
4
This article (不再可用)深入讨论垃圾收集器(概念上…有几种实现方式)。你文章的相关部分是“A.3.4不可及”:
|
![]() |
7
0
垃圾收集通常并不意味着“如果没有其他东西指向某个对象,则清除该对象”(即引用计数)。垃圾收集大致意味着查找无法从程序访问的对象。 因此在您的示例中,在a、b和c超出范围之后,它们可以被gc收集,因为您不能再访问这些对象了。 |
![]() |
8
0
比尔直接回答了你的问题。正如amnon所说,垃圾收集的定义只是引用计数。我只想补充一点,即使是像mark和sweep以及copy这样非常简单的算法也可以轻松地处理循环引用。所以,没什么神奇的! |
![]() |
codeforester · 测量GC暂停时间的最佳方法是什么? 7 年前 |
![]() |
Venki WAR · 需要解释G1的并行完整GC 7 年前 |
![]() |
Stephan_Berlin · 为什么CMS系列中的初始标记阶段 7 年前 |
![]() |
Bonsaisteak · 为什么年轻一代需要三个区域来收集垃圾? 7 年前 |
![]() |
goks · 如何清除熊猫的数据帧内存? 7 年前 |