垃圾收集器如何知道堆栈帧引用?(How do garbage collectors know abo

2019-07-29 14:52发布

什么技术做现代的垃圾收集器(如CLR,JVM)用来判断哪些堆中的对象从堆栈中引用

具体怎么可以在虚拟机从知道哪里是栈开始解释堆对象的所有局部引用下班回来?

Answer 1:

在Java(和可能在CLR虽然我知道它的内部较差),字节码键入与对象VS原始信息。 其结果是,有在字节码中,描述哪些在每个堆栈帧的变量是对象的,哪些是基元的数据结构。 当GC需要扫描根集,它使用这些StackMapTables引用和非引用区分。

CLR和Java必须有一些像这样的机制,因为它们是精确的收藏家。 有喜欢保守的收藏家贝姆收集可治疗堆栈作为一个可能的指针上的每个偏移。 他们看看是否值(当作为指针处理)是偏移到堆中,如果是这样,他们将其标记为活着。



Answer 2:

看看这个在Artima从1996年8月的文章, Java的垃圾回收堆 ; 尤其是第2页 。

任何垃圾收集算法必须做两个基本的东西。 首先,它必须检测垃圾对象。 第二,它必须通过回收垃圾对象所使用的堆空间,并使其对程序可用。 垃圾检测通常通过定义一组根和从根部确定可达性来实现的。 一个目的是可到达的,如果有来自通过其执行的程序可以访问该对象根引用的一些路径。 根始终对程序访问。 这是到达从根部的任何对象被认为是活的。 这是不可达的对象被认为是垃圾,因为他们再也不能影响程序执行的未来进程。

在JVM根集是依赖于实现,但总是会包括局部变量的任何对象的引用。 在JVM中,所有对象驻留在堆上。 局部变量所在的Java堆栈,并执行的每个线程都有自己的堆栈。 每个局部变量或者是一个对象引用或基本类型,如int,char或浮动。 因此,任何JVM垃圾收集堆的根将包括每一个线程的堆栈上的每个对象引用。 根的另一个来源是任何对象的引用,如字符串,在加载的类的常量池。 所装载的类的常量池可以是指保存在堆上的字符串,如类名,超类名,超接口名,字段名,字段的签名,方法名和方法签名。

由根提到的任何对象是可到达的,并且因此是一个活对象。 另外,通过一个活动对象中提到的任何对象也可到达的。 该方案是能够访问任何可到达的对象,所以这些对象必须保持在堆上。 所有不可任意对象可以被垃圾收集,因为没有办法为程序来访问它们。

文章继续探索不同的垃圾收集策略,包括引用计数收藏家,收藏家跟踪,压缩收集器和复制收集。


虽然这篇文章是旧的,它今天仍然适用; 没有多少真正改变。 已经有性能方面的改进,以不同的收集策略,但没有新的重大进展。

甲骨文的HotSpot JVM中,例如,有一个新的垃圾,一是垃圾收集器是复制收集与性能调整为多核心处理器和大堆大小(见这个答案为更多的G1垃圾收集器)。



Answer 3:

有关这个主题的有趣的文件张贴由.NET团队后不久,他们就CoreCLR开源: 堆栈散步



文章来源: How do garbage collectors know about references on the stack frame?