据我所知,YGC所花费的时间与伊甸园中活物的数量成正比。我也理解在主要集合中如何计算实时对象(线程堆栈和静态对象中的所有对象以及可传递地从这些对象到达的其他对象。)
但是我不明白年轻一代的收藏中是如何计算出活物的?
如果它解析线程堆栈,那么它需要解析eden + tenured space,而我认为并非如此。那么JVM如何在eden中找到活动对象并将它们复制到To Survivor
空间?
答案 0 :(得分:8)
年轻一代收藏中如何计算出活体对象?
可以在this article中找到有关如何在HotSpot中实施分代集合的高级描述。
一般来说,世代收藏家将年轻一代标记如下(假设我们只有两代人):
在HotSpot中,使用“Card Table”标识包含年轻代引用的旧代对象。旧一代被划分为512字节的区域,并且每个区域具有“卡”。如果该地区包含任何旧的 - >新一代指针,卡中的一点设置。然后,在新一代集合期间跟踪设置了卡位的区域中的对象。
棘手的是维护Card表,因为新的空间引用被写入旧代对象。在HotSpot中,这是使用软件写屏障实现的,只要将新的空间参考写入与卡对应的存储区域,就会设置适当的卡的脏位。正如链接文章指出的那样,这使得在对象中设置参考字段更加昂贵,但由于能够在大多数时间只收集新一代节省时间,显然是值得的。
答案 1 :(得分:3)
为了追踪最年轻的一代,垃圾收集器扫描相同的根集(堆栈和寄存器)以及自上一代年轻扫描以来已修改的所有旧(未收集)代。只有那些已被修改的对象才可能指向年轻代对象,因为未修改的对象不可能指向上次修改后创建的对象。
所以棘手的部分是,GC如何知道自上次GC以来哪些对象已被修改?可以使用许多技术,但它们基本上归结为跟踪对旧代对象的写入。这可以通过捕获写入(写入障碍)或仅跟踪所有写入目标(写入缓冲区,卡片标记)来完成,所有这些都会在GC未运行时增加程序执行的开销(因此它不会显示为GC暂停时间,但显示在总耗用时间内)。如果可用,硬件支持可以提供很多帮助。跟踪不需要精确,只要扫描每个修改过的老一代对象(扫描未修改的对象是浪费时间,但不会伤害任何东西)。
答案 2 :(得分:1)
我在这里引用article by Brian Goetz的相关文字。
跟踪垃圾收集器,例如 复制,标记扫描和标记紧凑, 都从根集开始扫描, 遍历对象之间的引用, 直到所有活物都存在 参观。世代追踪 收集器从根集开始, 但不会遍历那些引用 导致旧的物体 一代,减少了 要跟踪的对象图。