Python 垃圾收集-是否标记+;扫描必须是单片的/原子的

Python 垃圾收集-是否标记+;扫描必须是单片的/原子的,python,memory,garbage-collection,micropython,Python,Memory,Garbage Collection,Micropython,本次讨论将使用micropython代码,但由于它非常简单,我希望它对mark+sweep的一般性讨论有用 使用垃圾收集,特别是标记和清理;让我们来定义一下 标记 在标记阶段,gc遵循内存引用,并从字面上标记所使用的内存块,以指示它们可以从根块集访问 扫描 标记阶段完成后,清扫器在整个堆上循环,如果使用了内存块,但未标记则表示代码无法访问该内存块,因此将其“释放”,即标记为空闲。在标记阶段标记的内存块已移除该标记 当前的实现需要一个原子调用来执行垃圾收集(也称为gc),但我一直在想,是否可以将

本次讨论将使用micropython代码,但由于它非常简单,我希望它对mark+sweep的一般性讨论有用

使用垃圾收集,特别是标记和清理;让我们来定义一下

标记
标记阶段,
gc
遵循内存引用,并从字面上标记所使用的内存块,以指示它们可以从根块集访问

扫描
标记阶段完成后,清扫器在整个堆上循环,如果使用了内存块,但未标记则表示代码无法访问该内存块,因此将其“释放”,即标记为空闲。在标记阶段标记的内存块已移除该标记

当前的实现需要一个原子调用来执行垃圾收集(也称为
gc
),但我一直在想,是否可以将其拆分为多个调用,而不是一个单片/原子调用

这将有助于减少抖动:与一次大的定时命中不同,您将有一组较小的呼叫分散开来。(这里不讨论如何“展开”gc调用的实现细节……除非有人认为这会增加讨论。)

如果
gc
是“在后台”运行的(在字节码之间),或者-那么在错误的点进行分配(或取消分配)可能会导致竞争条件和堆损坏。在分割执行之前,我们必须确定可能的竞争条件

可以执行的两个操作是:分配和解除分配

分配

如果用户在标记或扫描阶段中间执行分配,则会发生什么情况?

让我们看一个具体的代码示例

>> var1 = SomeAllocation()
标记期间的分配
在上面的示例中,在REPL中执行一条语句,因此对字典的任何添加都将被添加到全局字典中,全局字典是
GC根中的一个条目。如果一个条目在被扫描之前被添加到globals中,则不会发生任何“坏”情况:新的内存块将被标记为应标记的

问题是是否在扫描完全局后对其进行了修改。在这种情况下,内存块不会被标记为
,因此在扫描阶段,它将被视为“不可访问”并被释放。即使不应该

扫描期间的分配
如果在扫掠器遍历内存中的该点之前分配了一个块,它将释放该块,因为它没有来自标记阶段的特殊标记。如果在清扫器穿过所述块后分配块,则不会发生任何不良情况

解决方案

如果代码> GC 处于执行中,则将分配的块标记为<强>标记< /强>。唯一的缺点是,如果您分配同相扫描,并且在扫描程序检查了新分配的块之后,您将使用标记为标记的块完成

gc
。除非用户明确释放它,否则如果无法访问它,您将需要经历额外的
gc
周期来释放它

但有一个简单的解决方案:如果在相位扫描期间进行分配,则检查清扫器的位置:如果要分配的新块在其后面,则不要使用标记标记,否则,请使用标记,因为清扫器会删除标记。这样,您就不会退出带有标记的块的
gc

解除分配

如果用户在标记或扫描阶段中间执行分配,则会发生什么情况?

标记期间解除分配

如果在扫描引用(父)块之前释放了块,则不会发生任何事情

如果一个块被释放,并且它的子项已经被标记,我们就有不一致性,因为只有当它们的父项也被标记
(或者父项是
GC根
)时,块才应该被标记。结果是,这些不可到达但标记的块将在额外的
gc
循环之前不会被释放,因为已经标记了,这些父级较少但标记的块将不会通过相位扫描被释放

然而,我不认为这是一个问题,因为这与单片
gc
的情况没有任何不同。在单片
gc
中,您必须完成当前
gc
循环,然后用户将调用
free(ptr)
,然后在下一次
gc
期间释放该块的子块。堆处于“正确”状态之前的时间量不会改变

在扫描期间解除分配

如果一个块在清扫器检查之前被释放,则不会发生任何特殊情况。free操作将目标块的状态从marked更改为free,然后当清扫器到达时。这里没什么可看的,只有一个空街区

如果一个块在清扫器检查后被释放,则自由操作会将目标块的状态从已使用更改为自由

问题

我的分析是否正确:是否可以拆分mark+sweep垃圾收集?

是的,这是可能的

Java自1.4版(2002年)起就有了收集器。它的工作原理与您描述的类似


如果您运行,我想您今天可以在本地利用它。

不幸的是,它必须在micropython中进行移植/实现。但是谢谢你确认这个想法哈