NIM中的ARC/ORC简介

2020-10-15 22:33:00

让我们从一些历史开始:NIM传统上一直是一种垃圾收集(GC)语言。大多数标准库都依赖垃圾收集(GC)来工作。当然,您可以禁用GC并执行手动内存管理,但是这样您就无法访问大部分stdlib(顺便说一下,它相当大)。

很长一段时间以来,NIM中的默认GC一直是REFC(使用标记&;Sweep阶段进行周期收集的延迟引用计数),还有其他可用选项,如markAndSweep、Boehm和Go。

但是在过去的几年里,NIM有了新的想法,与析构函数相关,拥有ref(Newrun),以及类似的东西:

ARC的核心是一个基于自动引用计数的内存管理模型,带有析构函数和移动语义。有些人把Nim的ARC误认为Swift的ARC,但有一个很大的区别:NIM中的ARC不使用原子RC。

引用计数是释放程序未使用资源最常用的算法之一。任何托管(由运行库控制)引用的引用计数是该引用在其他地方使用的次数。当该计数变为零时,该引用及其所有基础数据都将销毁。

ARC和NIM GC之间的主要区别是ARC是完全确定性的-当编译器认为不再需要某个变量(字符串、序列、引用或其他变量)时,它会自动注入析构函数。从这个意义上说,它类似于C++及其析构函数(RAII)。为了说明这一点,我们可以使用NIM的expandArc自省(将在NIM 1.4中提供)。

Proc main=let mystr=stdin。ReadLine()case mystr of";hello";:ECHO";很高兴认识您!";BYE";:ECHO";再见!";QUIT()否则:放弃Main()。

然后通过运行Nim c--gc:arcandArc:main example.nim在Main过程上使用NIM的ARC IR。

Var mystr try:mystr=readLine(Stdin)case mystr of";hello";:ECHO[";很高兴见到您!";]of";BYE";:ECHO[";再见!";]退出(0)否则:放弃最终:`=销毁`(Mystr)。

我们在这里看到的非常有趣-NIM编译器将主进程的主体包装在try:Finally语句中(即使在try块中引发Exception时,Finally中的代码也会运行),并向mystr插入=Destroy调用(在运行时初始化),以便在不再需要它时(当它的生命周期结束时)销毁它。

这显示了ARC的主要功能之一:基于作用域的内存管理。作用域是程序中的一个单独的代码区域。基于作用域的MM意味着编译器将在作用域结束后自动为任何需要析构函数的变量插入析构函数调用。许多NIM构造引入了新的作用域:过程、函数、转换器、方法、块语句和表达式、for和while循环等。

ARC还有所谓的钩子(Hooks)-可以为类型定义的特殊过程,用于在销毁/移动/复制变量时覆盖默认的编译器行为。当您想要为您的类型创建ecustom语义、处理涉及指针的低级操作或执行FFI时,它们特别有用。

与NIM目前的REFC GC相比,ARC的主要优势包括(包括我上面提到的):

基于作用域的内存管理(作用域之后注入析构函数)-通常会减少程序的RAM使用量并提高性能。

移动语义-编译器静态分析程序并在可能的情况下将内存副本转换为移动的能力。

共享堆-不同的线程可以访问相同的内存,您不需要复制变量来在线程之间传递它们-而是可以移动它们。另请参阅关于在线程之间隔离和发送数据的RFC)

更简单的FFI(REFC需要每个外部线程手动设置GC,而ARC并非如此)。这也意味着ARC是创建从其他语言(.dll、.so、Python扩展名等)使用的NIM库的更好选择。

一般来说,ARC是程序变得更快、使用更少内存和具有可预测行为的惊人一步。

要为您的程序启用ARC,您只需使用--gc:arc开关进行编译,或将其添加到项目的配置文件(.nims或.cfg)中。

但是等等!我们是不是忘了什么?ARC是引用计数,众所周知,RC本身并不处理循环。简而言之,循环是指一些变量以一种类似于循环的方式相互依赖。让我们考虑一个简单的例子:我们有3个对象(A、B、C),每个对象都引用了另一个,最好用图表来表示:

要查找和收集该周期,我们需要有一个周期收集器-运行时的一个特殊部分,用于查找和删除程序中不再需要的周期。

在NIM周期中,收集已经由REFC GC的标记和清理阶段完成,但最好使用ARC作为基础来做得更好。这就把我们带到了:

ORC是NIM基于Arc的全新周期收集器,它可以被认为是一个成熟的GC,因为它包括一个本地跟踪阶段(与大多数其他执行全局跟踪的跟踪GC相反)。ORC是您在使用NIM的异步时应该使用的,因为它包含需要处理的周期。

ORC保留了ARC的大多数优势,除了确定性(部分)-默认情况下,ORC有一个用于收集周期的自适应阈值,并且出于同样的原因硬实时(部分)。要启用ORC,您需要使用--gc:orc编译您的程序,但是ORC在将来可能会成为NIM的默认GC。

ARC在NIM 1.2.x版本中可用,但由于一些已修复的错误,最好是在NIM 1.4版本(应该很快就会发布)中提供ARC和ORC可供广泛测试,但如果您渴望尝试它们,也可以选择1.4版本候选版本。

就这样!。感谢您阅读这篇文章-我希望您喜欢它,并将享受ARC/ORC给NIM带来的令人惊叹的可能性:)