pde*_*ter 4 haskell runtime ghc
例如
main = do
let ls = [0..10000000]
print ls
Run Code Online (Sandbox Code Playgroud)
这将使用O(1)内存创建数组"inplace".
以下编辑会导致程序在执行时耗尽内存.
main = do
let ls = [0..10000000]
print ls
print ls
Run Code Online (Sandbox Code Playgroud)
ls在这种情况下必须保存在内存中再次打印.实际上,在"就地"重新计算阵列时,实际上会有更多的内存效率,而不是试图将其保持在原位.不过那是个好消息.我真正的问题是"GHC如何以及何时与lsO(1)时间内创建的可以销毁的运行时系统进行通信?" 我知道活体分析可以找到这些信息,我只是想知道信息的使用位置.它是通过此信息的垃圾收集器吗?它以某种方式被编译掉了吗?(如果我查看GHC编译的核心,那么两个示例都使用eftInt,所以如果它是编译器工件,那么它必须在更深层次上发生).
编辑:我的问题更多的是关于找到优化发生的位置.我想也许是在GC中,它在编译步骤中通过一些活泼度检查提供了一些信息.由于答案到目前为止,我可能错了.这很可能发生在核心之前的某个较低级别,所以cmm也许?
edit2:这里的大多数答案都假设GC知道ls第一个例子中不再引用它,并且在第二个例子中再次引用它.我知道GC的基础知识,我知道数组是链表,等等.我的问题正是GC 如何知道这一点.答案可能只是(a)它从编译器获取额外信息,或者(b)它不需要知道这一点,编译器100%处理此信息
ls这是一个懒惰的列表,而不是一个数组.在实践中,它更接近另一种语言的流或生成器.
第一个代码工作正常的原因是它实际上从未在内存中包含整个列表.ls是懒惰定义然后逐个元素消耗print.随着print时间的推移,没有其他引用开头的ls列表项可以立即进行垃圾回收.
从理论上讲,GHC 可以意识到在两个打印件之间不将列表存储在内存中而是重新计算它更有效.然而,这并不总是令人满意的 - 如果只对事物进行一次评估,那么很多代码实际上会更快 - 而且更重要的是,这会使执行模型对程序员来说更加困惑.