如何解决对象是如何从堆中移除的?
我正在学习 Java 和所有不同代中的垃圾收集。我现在知道当一个对象在运行后没有被标记时,它会被扫描。不过我很好奇:这个清扫过程到底是什么?
我的理解是它从堆中删除死对象,堆存储在RAM中,但是删除工作究竟是如何进行的呢?操作系统是否公开了从 RAM 中删除特定块中数据的方法?
我猜它的作用等同于 C 中的 free() 函数的作用,所以我想这是该函数究竟做了什么的问题。
解决方法
JVM 具有用于 GC 系统的可插拔架构。因此,JVM 实际执行的操作完全取决于您插入的 GC 引擎。在 SO 帖子中解释所有内容的细节有点多,但基本要点:
-
JVM 很少调用 free 或 malloc。 JVM 是它自己的小系统,它mallocs 一个船载然后将保持它,通常永远(java 主要是为服务器设计的,并假设它得到的任何东西都是为它保留的,其他应用程序根本不需要它。它'如果不在服务器上,我会尝试玩得很好,但这不是 GC 的优化目标) - 如果您的 VM 在某个时候创建了 2GB 的东西,然后几乎所有这些都可以被 GC,它将是*,但是 VM保留它从操作系统获得的 2GB。理论是:嘿,在我有生之年,我不得不处理 2GB 的对象,我是一名服务器,很有可能我会被要求做一项工作,导致我迟早不得不再次处理 2GB,和 free/malloc 需要时间,所以为什么要费心呢?我将只保留 2GB 的页面给自己,因为我知道可以免费使用它来写入堆内容。
-
GC 倾向于在“页面”中工作 - 每个新创建的对象都在页面上的下一个可用字节组中运行。一旦整个页面被填满,它就会记住哪些对象是从 'eden' 出来的(如果你在单个方法的范围内创建一个对象,并且该对象从未被分配到任何地方的任何字段,并且该方法是现在完成,这意味着对象也必须完成。通常对于这个“第一代”(创建对象后的第一次,页面已满并且垃圾收集相关),JVM反向工作:它知道哪些对象尚未完成并将它们复制到一个新页面,全部位于该新页面的“前面”,然后只认为整个页面现在是空的。从这个意义上说,java可以以几乎零成本收集快速垃圾,因此 JVM 的性能优于基于 malloc 和 free 的 C 代码。这也意味着你应该制造大量垃圾。最好有一个通常不可变的类型,你可以不断地创建新的实例,而不是拥有一个寿命更长的实例。续ained 短期垃圾通常是免费的。
-
对于下一代(随着物体的存在,它们不断被推高“一代”,连续的几代被单独放置并且长时间未被收集。要点是:物体已经存在的时间越长活着,降低现在符合条件的机会。存活时间长(不符合收集条件)的对象往往继续不符合条件。除了第一代,GC 倾向于在“积极标记和清除”方式,从所有“活着”的对象开始,并制作一个可以通过它们到达的对象的扩展图,从而使那些也“活着”。但是一旦识别出垃圾,原理是相同的: 创建一个新页面,将非垃圾文件复制过来,然后将旧页面标记为空闲而不用零覆盖它,因为没有必要(java 不允许指针运算,因此,没有代码看到未覆盖的风险)页中的字节数)。
如果您知道过去的硬盘碎片整理程序是如何工作的 - 就是这样。
但请记住:这是一个过于简化的视图,它从各种 GC 实现中挑选了一些细节。 Java VM 具有可插拔的内存架构,并且 GC 的实际工作方式存在广泛差异。此处提到的技术(copy-alive-out-then-reuse-page、free-collect-fast-garbage、分代垃圾收集和mark-and-sweep)并不是每个可用于JVM 的GC 系统都普遍使用。
*) 快速垃圾,如果你的 GC 是带有“伊甸园”生成系统的分代,通常总是接近持续应用,但是一旦你从伊甸园开始,不要假设垃圾正在消失今天收集。如果 JVM 有足够的堆剩余,那么此刻绝对没有理由在收集上花费周期。有资格进行 GC 的东西在 DAYS 的堆中停留是完全可行的,因为无论如何服务器大多处于空闲状态,并且所有生成的对象都是快速垃圾并且不会超过 eden gen。这是为什么将操作系统对 VM 占用的内存指示的输出或 VM 自己的内存可用性报告视为特别有用的信息是不合适的众多原因之一,也是为什么你绝对不应该编写终结器的原因之一。假设您需要终结器执行的任何操作都不会及时清理垃圾。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。