Algorithm 什么是一个简单的垃圾收集算法,用于试验一个简单的解释器?

Algorithm 什么是一个简单的垃圾收集算法,用于试验一个简单的解释器?,algorithm,garbage-collection,interpreter,Algorithm,Garbage Collection,Interpreter,我一直在试验编程语言设计,现在需要实现一个垃圾收集系统。现在想到的第一件事是引用计数,但这不会处理引用循环。我在搜索算法时遇到的大多数页面都是关于在现有语言(如Java)中调优垃圾收集器的参考。当我找到任何描述特定算法的东西时,我没有得到足够的实现细节。例如,大多数描述包括“当您的程序内存不足时…”,这在具有大量交换的4GB系统上不太可能很快发生。因此,我要寻找的是一些具有良好实现细节的教程,例如如何调整何时启动垃圾收集器(即,在X次内存分配后收集,或每Y分钟收集一次,等等) 为了更详细地介绍我

我一直在试验编程语言设计,现在需要实现一个垃圾收集系统。现在想到的第一件事是引用计数,但这不会处理引用循环。我在搜索算法时遇到的大多数页面都是关于在现有语言(如Java)中调优垃圾收集器的参考。当我找到任何描述特定算法的东西时,我没有得到足够的实现细节。例如,大多数描述包括“当您的程序内存不足时…”,这在具有大量交换的4GB系统上不太可能很快发生。因此,我要寻找的是一些具有良好实现细节的教程,例如如何调整何时启动垃圾收集器(即,在X次内存分配后收集,或每Y分钟收集一次,等等)

为了更详细地介绍我要做的事情,我首先编写了一个类似于Postscript的基于堆栈的解释器,我的下一次尝试可能是一种基于Lisp方言之一的S-expression语言。我的目标是自我教育,并将各个阶段记录到“如何设计和编写解释器”教程中

至于到目前为止我所做的工作,我已经编写了一个简单的解释器,它实现了一种C风格的命令式语言,由堆栈机器风格的VM解析和处理(请参见lang2e.sourceforge.net)。但是这种语言在输入任何函数时都不会分配新的内存,也没有任何指针数据类型,因此当时并不需要任何类型的高级内存管理。在我的下一个项目中,我考虑从非指针类型对象(整数、字符串等)的引用计数开始,然后在单独的内存池中跟踪任何指针类型对象(可以生成循环引用)。然后,每当池的增长超过上一个垃圾收集周期结束时的X个分配单元时,请再次启动收集器


我的要求是,它不会太低效,但易于实现和清晰地记录(请记住,我想将其发展成一篇论文或一本书,供其他人遵循)。我目前在前面得到的算法是三色标记,但它看起来像是一代收集器会更好一些,但更难记录和理解。因此,我正在寻找一些明确的参考资料(最好是在线的),它包含足够的实现细节来启动我。

何时启动分配器可能是开阔的——当内存分配失败时,可以GC,或者每次删除引用时,或者在中间的任何地方都可以GC。 如果运行的代码包含得相当好,等到没有选择可能意味着永远不会使用GC。或者,它可能会在您的环境中引入巨大的停顿,并完全破坏您的响应时间、动画或声音播放

在每个
free()
上运行完整的GC可以在更多的操作中分摊成本,尽管整个系统可能因此运行较慢。你可以更容易预测,但总体来说速度较慢


如果您想通过人为限制内存来测试这个东西,您可以简单地在非常有限的资源限制下运行。运行ulimit-v1024,该shell生成的每个进程将只有1兆的内存可供使用。

有一本关于垃圾收集的好书。它被称为垃圾收集:用于自动动态内存管理的算法,非常优秀。我读过,所以我不推荐这个,因为你可以通过谷歌找到它。看看它

对于简单的原型设计,请使用标记和扫描或任何简单的非世代、非增量压缩收集器。只有当您需要提供来自系统的“实时”响应时,增量收集器才是好的。只要允许您的系统在任何特定时间点任意延迟,您就不需要增量系统。分代收集器通过假设对象的生命周期来减少平均垃圾收集开销

我已经实现了all(分代/非分代、增量/非增量),调试垃圾收集器相当困难。因为您希望专注于语言的设计,而不是调试更复杂的垃圾收集器,所以可以选择简单的垃圾收集器。我很可能会选择马克和斯威普


使用垃圾收集时,不需要引用计数。扔掉它。

我应该补充一点,我已经看到了一些垃圾收集器的描述,比如mark和sweep的变体,但是我看到的大多数页面都没有维基百科的文章好多少。例如,正如我在问题中提到的,他们说当内存变低时,要踢它。在大多数轻量级脚本的运行期间,这在现代系统上是不可能发生的,即使发生了,在启动收集器之前耗尽所有系统内存也不是件好事。像这样的细节是我要找的应该有足够的细节来实现它。@DerekPressnall如果您正在运行一个轻量级脚本,那么最好不要运行GC,因为它只会浪费时间。当进程退出时,内存将被释放。关于抛出引用计数,将有许多对象是高度瞬态的,大多数是临时在堆栈上的对象——例如“2*3+5”(或按RPN顺序,“2*3+5”将离开“6”在堆栈上,直到add操作符使用它。仅使用mark和sweep,GC似乎将非常频繁地启动。但是这是否仍然比开销更有效