【问题标题】:How does the Garbage Collection mechanism work? [closed]垃圾回收机制是如何工作的? [关闭]
【发布时间】:2010-10-20 22:27:09
【问题描述】:

用外行的术语来说,垃圾收集机制是如何工作的?

如何确定一个对象可用于垃圾回收?

另外,Reference Counting, Mark and Sweep, Copying, Train 在 GC 算法中是什么意思?

【问题讨论】:

标签: memory-management garbage-collection


【解决方案1】:

当您使用带有垃圾收集的语言时,您将无法直接访问内存。相反,您可以访问该数据之上的一些抽象。正确抽象的一件事是数据块在内存中的实际位置,以及指向其他数据块的指针。当垃圾收集器运行时(这种情况偶尔会发生),它会检查您是否仍然持有对它为您分配的每个内存块的引用。如果不这样做,它将释放该内存。

不同类型的垃圾收集器之间的主要区别在于它们的效率以及它们可以处理的分配方案类型的任何限制。

最简单的是正确的引用计数。当您创建对对象的引用时,该对象上的内部计数器会增加,当您偶然引用或它不再在范围内时,(前)目标对象上的计数器会减少。当这个计数器达到零时,对象就不再被引用并且可以被释放。

引用计数垃圾收集器的问题在于它们无法处理循环数据。如果对象 A 具有对对象 B 的引用,而对象 B 又具有对对象 A 的某些(直接或间接)引用,则它们永远不能被释放,即使链中的任何对象都没有在链外被引用(因此不是程序根本无法访问)。

另一方面,标记和扫描算法可以处理这个问题。标记和清除算法通过定期停止程序的执行来工作,将程序分配的每个项目标记为不可达。然后程序运行程序具有的所有变量并将它们指向的变量标记为可达。如果这些分配中的任何一个包含对程序中其他数据的引用,则该数据同样被标记为可访问等。

这是算法的标记部分。此时所有程序可以访问的东西,无论多么间接,都被标记为可达,而程序无法访问的所有东西都被标记为不可达。垃圾收集器现在可以安全地回收与标记为无法访问的对象关联的内存。

标记和清除算法的问题在于它效率不高——必须停止整个程序才能运行它,而且很多对象引用不会改变。

为了改进这一点,标记和清除算法可以扩展为所谓的“分代垃圾收集”。在这种模式下,已经在系统中进行了一定数量的垃圾回收的对象会被提升到老年代,而不是经常检查。

这提高了效率,因为对象往往会在年轻时死去(想想在循环中更改字符串,可能会导致几百个循环的生命周期)或寿命很长(用于表示应用程序主窗口的对象, 或 servlet 的数据库连接)。

更多详细信息可以在维基百科上找到。

基于 cmets 添加:

使用标记和清除算法(以及除引用计数之外的任何其他垃圾收集算法),垃圾收集不会在您的程序上下文中运行,因为它必须能够访问您的程序无法直接访问的东西。所以说垃圾收集器在栈上运行是不正确的。

【讨论】:

  • 清晰、简单、简洁。您在这里提到的一个关于标记和扫描的问题是它检查程序中的所有变量。如果我没记错,堆栈和堆中的对象存在引用,那么我们如何关联该GC进程在堆中运行。
【解决方案2】:
  • 引用计数 - 每个对象都有 一个计数,当 有人参考 对象,当有人时递减 释放参考。当引用计数变为零时,该对象被删除。 COM 使用 这种方法。
  • 标记和扫描 - 每个对象在使用时都有一个标记。从对象图的根(全局变量、堆栈上的局部变量等)开始,每个引用的对象都设置了它的标志,依此类推。最后,图中未引用的所有对象都将被删除。

slidedeck 中描述了 CLR 的垃圾收集器。幻灯片 15 上的“根”是首先进入图表的对象的来源。它们的成员字段等用于查找图中的其他对象。

Wikipedia 更详细、更详细地描述了其中几种方法。

【讨论】:

  • 我浏览了 wikipedia.. 实际上困扰我的是 Object Graph 它是如何被 GC 例程维护和遍历的。
  • 用构建对象图的 10k 视图更新了我的答案。
【解决方案3】:

垃圾收集只是知道你的程序中是否需要变量,如果没有,收集并删除它们。

重点是垃圾这个词,你家里用完的东西被扔进垃圾桶,垃圾人来帮你处理,把它捡起来带走为您的家庭垃圾桶提供更多空间。

引用计数、标记和扫描、复制、训练等在GC FAQ进行了详细讨论

【讨论】:

    【解决方案4】:

    一般的做法是在后台跟踪对象的引用次数,当这个数字变为零时,该对象将被垃圾回收,但是 GC 不会启动,直到它是明确需要的,因为它是一项昂贵的操作。当它启动时,GC 会遍历内存的托管区域并找到每个没有引用的对象。 gc 通过首先调用它们的析构函数来删除这些对象,允许它们自行清理,然后释放内存。通常,GC 会通过将每个幸存对象移动到一个内存区域来压缩托管内存区域,从而允许进行更多分配。

    就像我说的,这是我知道的一种方法,并且在这方面正在进行大量研究。

    【讨论】:

      【解决方案5】:

      Garbage collection是个大话题,实现的方法有很多。

      但简而言之,垃圾收集器会记录对通过 new 运算符创建的任何内容的所有引用,即使该运算符的使用对您隐藏(例如,在 Type.Create() 方法中) )。每次添加对对象的新引用时,都会确定该引用的 root 并将其添加到列表中(如果需要)。只要超出范围,引用就会被删除。

      当不再有对某个对象的引用时,它可以(不是“将”)被收集。为了提高性能并确保正确完成必要的清理,集合会同时针对多个对象进行批处理,并在多代中发生。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-10
        • 1970-01-01
        • 2013-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-11
        相关资源
        最近更新 更多