现代垃圾收集器(如在CLR,JVM中)使用什么技术来判断堆栈中堆对象 引用?
具体来说,VM如何从知道堆栈开始的位置解释堆对象的所有本地引用?
答案 0 :(得分:3)
在Java中(可能在CLR中虽然我知道它的内部结构不太好),但字节码是用对象与原始信息键入的。因此,字节码中有数据结构描述每个堆栈帧中的哪些变量是对象,哪些是基元。当GC需要扫描根集时,它使用这些StackMapTables来区分引用和非引用。
CLR和Java必须有这样的机制,因为它们是完全收集器。像boehm collector这样的保守收集器将堆栈上的每个偏移量视为可能的指针。他们查看值(当被视为指针时)是否是堆的偏移量,如果是,则将它标记为活动。
答案 1 :(得分:0)
从1996年8月Artima开始查看这篇Java's Garbage-Collected Heap文章;特别是page 2。
任何垃圾收集算法都必须做两件事。首先,它必须检测垃圾对象。其次,它必须回收垃圾对象使用的堆空间并使其可用于程序。垃圾检测通常通过定义一组根并确定来自根的可达性来完成。如果有一些来自根的引用路径,则执行程序可以访问该对象,则可以访问该对象。程序始终可以访问根。从根可以访问的任何对象都被认为是实时的。无法访问的对象被视为垃圾,因为它们不再影响程序执行的未来过程。
在JVM中,根集与实现有关,但始终包含局部变量中的任何对象引用。在JVM中,所有对象都驻留在堆上。局部变量驻留在Java堆栈上,每个执行线程都有自己的堆栈。每个局部变量都是对象引用或基本类型,例如int,char或float。因此,任何JVM垃圾收集堆的根将包括每个线程堆栈上的每个对象引用。根的另一个来源是常量加载类池中的任何对象引用,例如字符串。加载类的常量池可以引用存储在堆上的字符串,例如类名,超类名,超接口名,字段名,字段签名,方法名和方法签名。
根引用的任何对象都是可访问的,因此是活动对象。此外,活动对象引用的任何对象也是可访问的。该程序能够访问任何可访问的对象,因此这些对象必须保留在堆上。任何无法访问的对象都可以被垃圾收集,因为程序无法访问它们。
本文继续探讨不同的垃圾收集策略,包括引用计数收集器,跟踪收集器,压缩收集器和复制收集器。
虽然这篇文章很旧,但今天仍然适用;没有多少真正改变。不同的收集策略已经有了性能改进,但没有新的重大进步。
例如,Oracle HotSpot JVM有一个新的Garbage-First Garbage Collector,它是一个复制收集器,可以对多核处理器和大堆大小进行性能调整(有关G1垃圾收集器的更多信息,请参阅this answer) )。答案 2 :(得分:0)
.Net团队在他们制作CoreCLR开源后不久发布了有关此主题的有趣文档:Stack Walking