垃圾收集机制如何运作?

S M*_*ran 23 garbage-collection memory-management

在一个非专业术语中,垃圾收集机制如何工作?

如何识别对象是否可用于垃圾回收?

另外,Reference Counting, Mark and Sweep, Copying, TrainGC算法的意思是什么?

tom*_*jen 36

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

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

最简单的是适当的引用计数.当您创建对象的引用时,该对象上的内部计数器会递增,当您有可能引用它或它不再在作用域中时,(前)目标对象上的计数器会递减.当此计数器达到零时,该对象根本不再被引用并且可以被释放.

引用计数垃圾收集器的问题是它们无法处理循环数据.如果对象A具有对对象B的引用,并且对对象A具有一些(直接或间接)引用,则它们永远不会被释放,即使链中没有任何对象被引用到链外(因此也不是) t可以访问该程序).

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

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

标记和扫描算法的问题在于效率不高 - 必须停止整个程序才能运行它,并且很多对象引用都不会改变.

为了改进这一点,可以使用所谓的"分代垃圾收集"来扩展标记和扫描算法.在此模式下,系统中已存在一定数量垃圾收集的对象将被提升为旧代,而这些对象通常不会被检查.

这提高了效率,因为对象倾向于年轻(想到一个字符串在循环内被改变,导致可能有几百个循环的生命周期)或活得很长(用于表示应用程序主窗口的对象,或者servlet的数据库连接).

在维基百科上可以找到更详细的信息.

根据评论添加:

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

  • 清晰,简单,简洁.你在这里提出一个关于标记和扫描的问题,它会检查程序中的所有变量.如果我没有错误引用堆栈中的对象和堆中的对象,那么我们如何将该进程与Heap中的GC进程相关联. (3认同)

TSt*_*per 5

垃圾收集只是了解程序中未来是否需要变量,如果不需要,则收集并删除它们。

重点是垃圾这个词,你家里完全用完的东西被扔进垃圾桶,垃圾工会来帮你处理它,把它捡起来并把它拿走,为你的房子垃圾桶腾出更多空间。

引用计数、标记和清除、复制、训练等在GC FAQ中有详细讨论


Mic*_*ael 5

  • 引用计数 - 每个对象都有一个计数,当有人引用该对象时该计数会增加,而当有人释放该引用时该计数会减少。当引用计数变为零时,该对象将被删除。COM 使用这种方法。
  • 标记和清除 - 每个对象都有一个标志(如果正在使用)。从对象图的根部(全局变量、堆栈上的局部变量等)开始,每个引用的对象都会设置其标志,依此类推。最后,图中未引用的所有对象都将被删除。

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

维基百科更详细地描述了其中几种方法。