【问题标题】:How exactly are objects removed from the heap?对象究竟是如何从堆中移除的?
【发布时间】:2021-06-03 15:45:03
【问题描述】:

我正在学习 Java 和所有不同世代的垃圾收集。我现在知道,当一个对象在运行后没有被标记时,它就会被清扫。不过我很好奇:这个全面的过程到底是什么?

我的理解是它从堆中删除死对象,并且堆存储在 RAM 中,但是删除究竟是如何工作的?操作系统是否公开了从 RAM 中删除特定块的数据的方法?

我猜它的作用相当于 C 中的 free() 函数的作用,所以我想这是一个关于该函数究竟做了什么的问题。

【问题讨论】:

  • 没有必要按照你建议的方式“删除”它; JVM 只是将该空间标记为可用于稍后写入。
  • 谢谢,这是有道理的。那么我的下一个问题是 JVM 如何找到下一个可用空间?它是否保留了所有可用空间的地图,或者 GC 的压缩部分是否意味着它可以知道可用空间从哪里开始?
  • 它有一个内部分配系统,执行与malloc/free相同的职责。 JVM 实现之间的细节有所不同。
  • 一个常见的实现是将保留的对象移动到一个新空间,因此用于新对象分配的所有空间变得空闲,无需跟踪任何特殊内容。这是generational GC strategy

标签: java memory-management garbage-collection


【解决方案1】:

JVM 具有用于 GC 系统的可插拔架构。因此,JVM 实际所做的完全取决于您插入的 GC 引擎。在 SO 帖子中解释所有内容的细节有点多,但基本要点:

  • JVM 很少调用 free 或 malloc。 JVM 是它自己的小系统,它会分配一个小船负载,然后通常永远保留它(java 主要是为服务器设计的,并假设它得到的任何东西都是为它保留的,其他应用程序不需要它。它如果不在服务器上,我会尝试玩得很好,但这不是 GC 的优化目标)——如果你的虚拟机在某个时候创建​​了 2GB 的东西,然后几乎所有这些东西都可以被 GC,它会是*,但是虚拟机保留从操作系统获得的 2GB。理论是:嘿,我不得不在我有生之年早些时候处理价值 2GB 的对象,我是一个服务器,很可能我会被要求做一项工作,导致我迟早不得不再次处理 2GB,并且 free/malloc 需要时间,所以为什么要为此烦恼呢?我将只保留 2GB 的页面给自己,因为它可以免费用于将堆内容写入其中。

  • GC 倾向于在“页面”中工作——每个新创建的对象都会进入页面上下一个可用的 o 字节。一旦整个页面已满,它就会记住哪些对象从“伊甸园”中出来(如果您在单个方法的范围内创建一个对象,并且该对象永远不会被分配给任何地方的任何字段,那么该方法就是现在完成了,这意味着对象也必须完成。通常对于这个“第一代”(创建对象后的第一次,页面已满并且垃圾收集相关),JVM反向工作:它知道哪些对象尚未完成并将它们复制到一个新页面,全部位于该新页面的“前面”,然后只认为整个页面现在是空的。从这个意义上说,java可以以几乎零成本收集快速垃圾,并且 JVM 优于基于 malloc 和 free 的 C 代码,因此。这也意味着你应该制造大量垃圾。最好有一个通常不可变的类型,你不断制作新的实例,而不是拥有一个寿命更长的实例。续短命的垃圾通常是免费的。

  • 对于下一代(随着物体继续存在,它们会不断被推高一个“一代”,连续几代被单独放置并且在更长的时间内未被收集。要点是:一个物体已经存在的时间越长, 降低它现在符合条件的机会。寿命长的对象(不符合收集条件)往往继续不符合条件。除了第一代之外,GC 倾向于在“积极”中工作标记和清扫”的方式,从所有“活着”的对象开始,并制作一个您可以通过它们到达的对象的扩展图,从而使这些对象也“活着”。但是一旦识别出垃圾,原理是一样的:制作一个新页面,复制非垃圾,然后将旧页面标记为空闲而不用零覆盖它,因为没有必要(java不允许指针运算,因此,代码没有风险看到未覆盖的字节在页)。

如果您知道硬盘碎片整理程序在过去是如何工作的 - 就是这样。

但请记住:这是一个过于简化的视图,它从各种 GC 实现中提取了一些细节。 Java VM 具有可插拔的内存架构,并且 GC 的实际工作方式之间存在广泛的差异。此处提到的技术(copy-alive-out-then-reuse-page、free-collect-fast-garbage、分代垃圾收集和标记和清除)并不是所有 JVM 可用的 GC 系统都普遍使用的。

*) 快速垃圾,如果你的 GC 是分代的,并且内置了一个“伊甸园”生成系统,通常总是接近持续应用,但是一旦你从伊甸园一代继续前进,不要假设垃圾正在消失今天收集。如果 JVM 有足够的堆剩余,那么此时绝对没有理由在收集上花费周期。符合 GC 条件的东西在堆中停留 DAYS 是完全可行的,因为无论如何服务器大多处于空闲状态,并且所有生成的对象都是快速垃圾,并且不会超过 eden gen。这是不适合将操作系统的 VM 占用内存指示的输出或 VM 自己的内存可用性报告视为特别有用的众多原因之一,也是您绝对不应该编写终结器的原因之一。假设您需要终结器执行的任何操作都不会及时清理垃圾。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多