【问题标题】:Garbage collection young generation scanning垃圾回收年轻代扫描
【发布时间】:2014-12-04 12:24:56
【问题描述】:

我正在尝试了解垃圾收集机制,并且我正在研究代算法,并且我有一个关于年轻/老一代差异的问题。我读到开始在年轻代 GC 中收集对象是从 GC 根开始标记它们以找到活动的对象,通常它将它们复制到幸存者空间,清除年轻代区域,瞧。

如果我们从 GC 根开始并开始遍历活动对象,我不明白我们是否也在老一代中找到对象?这是否意味着当我们在旧空间中击中一个对象时,我们会在该点停止跟踪引用还是什么?

【问题讨论】:

  • 简单的答案是肯定的。年轻代集合不会跟踪/标记老一代中的对象。当年轻代收集器发现一个年轻到老的引用时,它会忽略它。

标签: java garbage-collection


【解决方案1】:

当 GC 在年轻代中运行时,它被称为 Minor Collection。 Old Generation 中的对象不受此类集合的影响。

是的,可以从根直接访问的对象被标记为活动的,但它们可以位于堆中的其他位置,因此它们可以是旧代中的对象。

即使 Old Gen 对象是可访问的,Minor Collections 也不会在 Old Gen 中回收垃圾。

引用HotSpot doc

当年轻代填满时,它会在 只收集年轻一代;其他垃圾 世代不回收

对我来说,这意味着 GC 将遍历对象图,并可能在 OldGen 中找到垃圾但不会为它回收。

我找到了这个IBM article,它很好地解释了代际引用跟踪在 HotSpot GC 中的工作原理。

【讨论】:

  • 但这正是我的问题,老一代对象怎么可能不受这种类型的集合的影响?如果它们还活着,就必须从 GC 根中引用它们,不是吗?
  • 是的,OldGen 对象可以从根目录访问。正如 Stephen C 所说,小回收不会回收其他代的垃圾,即使它们是可访问的。
【解决方案2】:

虽然我没有直接检查过这一点,但常识表明每次遇到来自老一代的对象时都会减少对象图遍历。请注意,这种检查的成本很低:对指针值进行简单的范围检查就足以确定对象在堆区域内的位置。

然而,还有一个重要的问题需要考虑:如果一个年轻的对象只能通过一个旧的对象访问怎么办?显然,必须考虑以某种方式考虑老一代。

输入卡片表:这是每个堆区域前面的后备结构,其中保存了该区域的压缩“位图”视图,因此每个位对应于例如 256 个字节堆。每次更新引用类型变量时,卡表中的相应位都会升为 1,表示“脏”。

在卡片表就位后,每个 YG 集合都会发生以下情况:扫描所有标记为“脏”的堆块以查找指向年轻代对象的指针。以这种方式找到的每个对象都被认为是可达的。

上述推论:通过同时已成为垃圾的旧对象可访问的年轻对象将被视为可访问并污染堆,直到发生 Major GC。

【讨论】:

  • 谢谢马尔科!你触及了我下一个问题的主题——卡片。卡区有 256 个字节,但据我了解,它是一个行内存,你需要知道相应的类才能理解它。所以如果我们知道内存区域,我们怎么知道它持有什么或者它持有引用呢?那里还有什么? :)
  • 是的,我很熟悉这个问题,但不知道细节。例如,可以扫描内存以查找对象标头的足迹。当您知道标题时,您就知道类。此外,每个单词可能假定是一个指针,然后取消引用以查看它是否指向有效的对象标头。这是启发式方法,但它可能“足够好”。
  • 我认为不需要启发式。 JVM 可以根据每个对象头中的节点大小信息迭代对象。或者它可以记录每张卡片(或一系列卡片)中第一个对象头的地址,并以此为基础进行迭代。
  • @StephenC 好点...记录第一个对象的地址确实为我敲响了警钟。对于跨越卡片的对象也有一些特殊处理。
  • 任何时候系统接触到一个老一代的对象,它就会知道它正在这样做。我希望保留一个已被触及的老一代对象列表会比遍历所有老一代对象更便宜。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 1970-01-01
  • 2011-02-21
  • 2018-10-15
  • 1970-01-01
相关资源
最近更新 更多