OCaml 的 local 值如何使用独立的栈

原标题How OCaml Locals Use a Separate Stack

一个列表例子展示了限定在区域内的 local 值如何避免反复进行需要垃圾回收的内存分配。

频道
Jane Street
发布
2024年2月29日
视频
11:07
阅读
3 分钟
幻灯片
3
原文
英语
在 YouTube 打开
往下滚动阅读时,视频会缩到右下角继续播放。字幕跟随阅读语言。
阅读语言共 2 种语言可读
由 AI 从英语原文翻译。打开“对照原文”可以逐段核对。
摘要

30 秒看懂

在这期 OCaml Unboxed 中,讲者比较了堆分配和垃圾回收与独立 local 栈上的分配。循环例子展示了不逃逸的值如何在区域结束时回收,以及 local 值为什么可能需要在函数返回后继续存在。

  1. 1反复进行堆分配每次迭代都会构建新列表,引用改变后,之前的列表变得不可达。
  2. 2回收的成本简化的标记清除例子展示了回收堆对象所需的工作和可能的暂停。
  3. 3区域限定生命周期在循环体内分配的 local 值不能逃出该区域。
  4. 4为什么需要独立栈exclave 可以让值在函数返回后继续存在,同时仍限制在外围区域内。

要点建议

  1. 不使用 local 时,例子会反复在堆上分配列表。
  2. 垃圾回收会回收不可达的值,但可能增加工作量和延迟。
  3. 循环体形成一个区域,其中的 local 值不能逃逸。
  4. 区域结束后,可以一起回收并复用其中的 local 分配。
  5. local 栈与调用栈分开,因为一些 local 值的寿命长于分配它们的函数。
全文

按章节阅读整理后的全文

只看原始文稿
01

列表分配示例

讲者重新审视一个通过 local 注解减少垃圾回收分配的程序。例子反复构建和处理列表。

在这期 OCaml Unboxed 中,我继续探索我的 Jane Street 同事和我正在开源编译器分支中开发的 local 模式。之前的例子通过 local 注解减少了需要垃圾回收的分配。今天我想展示内存去了哪里,以及这种做法为什么有效。

例子的主函数 doit 使用一个迭代变量和一个列表进行循环。它调用 init 构建列表,然后计算其中 5 的倍数的个数。首先,假设程序没有 local 注解,观察堆上的分配。

02

堆分配与垃圾回收

不使用 local 时,旧列表变得不可达,随后由垃圾回收机制回收。讲者用简化的标记清除模型解释其成本。

init 在堆上构建由 cons 单元组成的链表,list 变量指向列表开头。下一次迭代中,init 构建另一个列表,list 改为指向新列表。旧单元无法再通过该变量访问。

垃圾回收运行时,简化后的过程是从栈变量等根开始追踪,标记可达的堆对象,并回收不可达对象。当前列表仍然存活;旧列表可以被回收,为后续分配腾出空间。

追踪可达的堆单元
幻灯片 1 / 3追踪可达的堆单元图中展示了调用栈引用,以及可达和不可达的列表单元。

垃圾回收很有价值:它支持不可变的函数式编程,使程序更容易推理和开发。但寻找存活数据并回收其余数据需要工作。在标记清除模型中,回收可能暂停程序执行,并访问可能挤掉更有用缓存数据的内存。

Jane Street 的大多数程序使用垃圾回收都没有问题。但对于延迟敏感的场景,我们希望避免这些暂停和其他减速。这一性能目标促使我们研究 local。

03

独立的 local 栈

local 分配被限制在区域内,可以在区域结束时一起回收。独立的栈允许值在函数返回后继续存在,又不逃出其区域。

现在来看使用 local 的版本。调用栈仍然保存 doit 及其变量,但 init 在一个独立区域中分配列表单元,我称之为 local 栈。它既不是普通调用栈,也不是由垃圾回收管理的堆。

init 完成并返回局部分配的列表,doit 可以用它计算 5 的倍数的个数。循环体是一个区域:在该区域内分配的 local 值不能逃出去。迭代结束时,分析保证这些分配不再需要。

独立的 local 栈
幻灯片 2 / 3独立的 local 栈列表单元分配在与调用栈和堆分开的区域。

运行时可以一起回收该区域的 local 分配,并在下一次迭代中复用同一块内存。释放操作可以简单到只需改变下一次分配所用的指针,从而避免堆示例中描述的标记清除工作。

回收区域
幻灯片 3 / 3回收区域草图展示了一次迭代结束时旧的 local 分配被丢弃。

独立的 local 栈很重要,因为 init 可以在调用者用完列表之前返回。在 exclave 内创建的值可以在函数返回后继续存在,同时仍限制在外围区域内。函数栈帧和区域的生命周期并不总是相同,因此这些 local 分配不能简单地放在 init 的调用栈帧中。

同频道的其他文章

6 张幻灯片15:33EN → 简体中文
JSJane Street· 2026年10月26日Figgie 策略:解读手牌、争夺多数与定价Bradley, Mike · Jane StreetJane Street 交易员 Bradley 和 Mike 分析三局游戏,展示私人信息、市场竞争和时机如何影响牌价。Decision MakingMathematicsFintech
1:48:29EN → 简体中文
JSJane Street· 2026年10月16日AI 如何改变编程:John Krazit 与 Ron Minsky 的对话Ron Minsky, John Krazit · Jane StreetJane Street 的 AI 工具负责人和 Signals and Threads 主持人探讨智能体基础设施、安全、代码审查,以及软件开发体验的变化。编程智能体Developer productivity评估+2
1:36:37EN → 简体中文
JSJane Street· 2026年9月23日Aaron Bauer:在 AI 时代教授软件工程Ron Minsky, Aaron Bauer · Jane Street当模型能够生成代码时,学习目标、主动练习和编辑器设计如何影响工程教育。AI in EducationSoftware engineeringEducation+2
9 张幻灯片1:05:45EN → 简体中文
JSJane Street· 2026年9月11日Cyrus Omar:实时编程与人与 AI 共享的计算公共空间Cyrus Omar通过 Hazel 演示,探讨即时反馈、结构化协作和精细权限如何帮助人类与 AI 智能体共同工作。Programming LanguagesHuman-AI Collaboration开发流程与测试+2
1:25:00EN → 简体中文
JSJane Street· 2026年9月2日Eric Mannes:如何将杂乱的外部数据用于交易研究Ron, Eric Mannes · Jane Street从商品期货和 Excel 风险系统,到时点数据集和 AI,Eric Mannes 解释 Jane Street 数据工程背后的领域知识。Data quality & curation开发流程与测试Investing+2
7 张幻灯片1:16:29EN → 简体中文
JSJane Street· 2026年8月26日Grant Sanderson 与 Alok Puranik:从群论看位置编码Grant Sanderson, Alok Puranik · 3Blue1Brown从注意力机制的假设出发,他们推导矩阵指数,并将旋转、衰减和 Jordan 块与 RoPE、ALiBi 联系起来。Transformers & attentionMathematics机器学习基础+1