2011-12-12 305 views
7

我最近阅读了关于垃圾回收的一些小部分(大部分是用Java编写的),有一个问题仍然没有答案:JVM(或者一般的运行时系统)如何跟踪当前的活动对象?垃圾回收 - 根节点

我知道那里的对象是当前在堆栈中的对象,所以所有的局部变量或函数参数都是ARE对象。这个问题的解决方法是,无论何时运行时系统检查堆栈中当前是什么,它将如何区分参考变量和简单的int?它不能,可以吗?

因此,必须有某种机制,以允许在运行时建立活动对象初步名单以通为标志扫描阶段的...

回答

4

我发现greyfairer提供的答案是错误的。 JVM运行时不会通过查看用于在堆栈上推送数据的字节码来收集堆栈的根集。堆栈帧由4个字节(32位拱)插槽组成。每个插槽可以是对堆对象的引用或像int这样的原始值。当需要GC时,运行时从上到下扫描堆栈。对于每个插槽,如果包含参考文件:

a。它在4字节的边界对齐。

b。插槽中的值指向堆的区域(在下限和上限之间)。

c。 allocbit已设置。 allocbit是一个标志,表示与其对应的内存位置是否被分配。

这里是我的参考:http://www.ibm.com/developerworks/ibm/library/i-garbage2/

还有一些其他技术可以找到根集(而不是Java)。例如,因为指针通常在4/8字节边界处对齐,所以第一位可以用来指示一个时隙是基元值还是指针:对于基元值,第一位设置为1.缺点是你只有31位(32位拱)来表示整数,并且对原始值的每个操作都涉及移位,这显然是一个开销。

此外,您可以使所有类型包括int分配在堆上。也就是说,所有的东西都是物体。然后,堆栈帧中的所有槽都是引用。

+0

因此,总而言之,它是相当低层次的差异化,而不是JVM?但JVM有一个为字节码声明的引用类型,所以为什么不使用它呢?您确定它的级别如此之低,而不是字节代码级别? – Bober02

+1

据我所知(基于我之前给出的链接以及浏览几个JVM实现的代码),我相信我的理解是正确的。您可以简单地深入一些开源JVM实现的GC代码来检查这一点。他们都需要走栈以找出参考。但是,也许用于验证插槽是否为引用的标准略有不同(大多数验证a。和b。对于c,它实际上是基于实现的)。 – Rainfield

+0

为什么不使用字节码,这是我的理解(不知道它是否正确)。 GC是一个运行时间的东西,但字节码是在编译时和静态时生成的。当GC发生时,运行时系统需要找出根并跟踪它们以找出活动对象。 。要做到这一点,你必须实际检查每个堆栈帧的值,即使你知道这个槽在编译时包含一个引用(正如greyfairer所说,通过查看字节码你可以知道这一点)。因为您需要知道确切的参考值才能找到堆中的其他对象。 – Rainfield

2

运行时可以参考的变量和原语之间的完美区分,因为这是在编译的字节码中。例如,如果一个函数f1调用一个函数f2(int i,Object o,long l),调用函数f1将在表示i,4(或8?)的堆栈(或寄存器)上推4个字节。 )为o的引用字节,l为8个字节。被调用的函数f2知道堆栈中哪些位置可以找到这些字节,并且可能会将引用复制到堆上的某个对象。当函数f2返回时,调用函数将从堆栈中删除参数。

运行时解释字节码并记录它在堆栈上压入或下落的内容,因此它知道什么是引用,什么是原始值。

根据http://www.javacoffeebreak.com/articles/thinkinginjava/abitaboutgarbagecollection.html,java使用tracing garbage collector而不是引用计数算法。

+0

谢谢你的回答。考虑到这一点,垃圾收集在JVM启动时如何进行?它如何实际定位根节点 - 跳回堆栈,还是有单独的节点集合? – Bober02

+0

查看文章链接进行深入解剖。 – greyfairer

+0

我在您引用的文章中找到以下句子'标记和扫描遵循从堆栈和静态存储开始并通过所有句柄跟踪来查找活动对象的相同逻辑。'这些神秘的手柄是指什么...... – Bober02

0

HotSpot VM为编译的每个子例程生成GC映射,其中包含有关根的位置的信息。例如,假设它已经编写了子程序机器代码(其原理是字节代码相同),这是120个字节长,那么它的GC地图可能是这个样子:

0 : [RAX, RBX] 
4 : [RAX, [RSP+0]] 
10 : [RBX, RSI, [RSP+0]] 
... 
120 : [[RSP+0],[RSP+8]] 

这里[RSP+x]是应该指示堆栈位置和R??寄存器。因此,如果线程在偏移10的汇编指令处停止并且运行gc循环,则HotSpot知道三个根在RBX,RSI[RSP+0]。它跟踪这些根,并在必须移动对象时更新指针。

我为GC图描述的格式只是为了演示原理,显然不是一个HotSpot实际使用的格式。它并不完整,因为它没有包含关于包含原始活动值的寄存器和堆栈槽的信息,并且对于每个指令偏移量使用列表都没有空间效率。您可以通过多种方式以更高效的方式打包信息。