2024 年 Clojure 状态调查!中分享您的想法。

欢迎!请查看关于页面,了解更多关于这一机制的信息。

0
core.async

运行此代码最终会抛出 OOME

`
(let [c (a/chan)]
(a/go (while (a/<! c)))
(a/go

(when-some [xs (range)]
  (doseq [x xs]
    (a/>! c x)))))

`

这个(使用 {{let}} 而不是 {{when-some}})可以正常工作

`
(let [c (a/chan)]
(a/go (while (a/<! c)))
(a/go

(let [xs (range)]
  (doseq [x xs]
    (a/>! c x)))))

`

在前者中,range 序列被存储在堆上(在 go 块的状态数组中),并在整个 doseq 迭代过程中保留,尽管在循环初始化之后不再需要。
在后者中,range 序列存储在栈上,编译器可以执行其局部清理的魔法。

对于跨越多个 ssa 块的每个值,都可能出现这种行为。

3 答案

0

评论者:alexmiller

问题实际上不是当-some 实际上是一个 let,并且你在 let 中持有无限范围的头部吗?

0

评论者:leonoel

我使用一个不那么牵强的例子更新了描述。
问题发生是因为 let 绑定包裹了一个控制流表达式。这实际上将值从栈移动到堆上,阻止编译器清理引用。

0
参考:[https://clojure.atlassian.net/browse/ASYNC-219](https://clojure.atlassian.net/browse/ASYNC-219)(由leonoel报告)
...