我正在研究一种玩具过程语言的业余编译器/解释器,并且我已经实现了我打算探索的大部分功能,除了一个好的垃圾收集算法(类似于 this guy )。我已经阅读了很多关于各种算法的内容,并且对如何实现它们有了大致的了解。我的语言运行时的早期迭代使用了引用计数,但我放弃了它以学习更高级的东西,所以我现在正在考虑标记和复制压缩算法。

我开始的第一个问题是阻止算法在 native 扩展函数(即用 C 编写的函数)中收集“对象”。根集由解释器堆栈上的“对象”和符号表中的“对象”组成,我不应该对这些有太多麻烦,但是,如果在 C 函数中创建容器“对象”,然后填充子“对象”,我怎样才能阻止 GC 收集它们,因为它实际上不在解释器堆栈上或绑定(bind)到符号?

使实现 GC 更容易的事情:

  • 我的语言中的所有“对象”都是内置类型(例如,不是面向对象的)
  • 解释器堆栈只是指向结构体的指针堆栈
  • 符号表只是指向结构体的指针数组

  • 用户代码:
    f = open('words.txt', 'r');
    lines = readlines(f);
    close(f);
    

    解释器(解析后,编译为字节码...):
  • push 文件名,open_mode
  • 调用 builtin_fopen 返回一个包装 FILE*
  • 的结构体
  • 将结果存储在符号中 f
  • 推送符号 f
  • 调用 builtin_flines 创建一个列表类型 l ,然后使用 C fread 读取每一行
    文件作为字符串类型,将其附加到列表 l
  • 将结果存储在符号 lines 中,依此类推....

  • 现在,如果在分配文件中包含一行的字符串之一时 GC 运行,则根集还没有对 l 的任何引用,因此应该收集它。
    关于如何更好地处理这个问题的任何想法?

    最佳答案

    由于我是你提到的最初的“这个”人,尽管我可以根据我迄今为止在项目中设计的内容,就你的第一个问题给你一些见解(我保证我最终会写博客)。所以首先,所有内存分配都通过一个增变函数。输入参数是您正在创建的对象类型,以及对指向它的指针类型对象的引用。然后在创建新对象时更新该指针对象。如果一个对象被分配给解释器运行时中一个 C 函数的独占使用,那么它就是一个根对象。在这种情况下,NULL 作为第二个参数传递,并将对象添加到根对象列表中。稍后,如果该内部函数不再需要该对象,则必须从根对象列表中删除该对象。 (它不会取消分配对象本身,因为它最终将由垃圾收集例程处理)。哦,解释器堆栈本身也是解释器中的一个对象(列表类型或数组类型对象),因此指向它的指针也在根对象列表中(同样,另一个列表类型对象也是解释器知道)。指向根对象列表的指针是垃圾收集器需要知道的唯一指针。

    此外,至于何时开始垃圾收集运行——由于现代架构上的内存实际上是无限的,我决定在分配了 X 个对象时启动垃圾收集器。运行后,您还剩下 Y 个对象。如果 Y 仍然大于 X 的 Z 百分比,则 X 会被提升到足以使之如此。然后我只希望 malloc() 永远不会失败(如果它失败了,我只是抛出一个错误并退出解释器)。

    希望这会有所帮助,并希望其他人会添加更多说明,因为在语言/解释器设计方面,我更像是一个业余爱好者。

    关于c - 用 C 实现的解释器中的垃圾收集问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15867941/

    10-09 06:09