使用-O2编译Haskell会大大增加内存使用量

时间:2014-10-12 04:11:29

标签: haskell memory optimization map ghc

这个简单的程序在使用ghc:

编译时没有标志的情况下在常量内存空间中运行
import Data.List
f x = x*x
g a = foldl' (+) (f a) [1..(1073741824-1)]
main = do putStrLn $ show $ foldl' (+) 0 $ map g [0,1]

使用ghc -O2编译时,内存使用量超过系统资源(8GB)。

将main更改为:

main = do putStrLn $ show $ foldl' (+) 0 [g 0, g 1]

缓解了问题所以它似乎与地图有关。

任何人都可以解释这种行为,也许可以解决这个问题吗?

GHC版本是:格拉斯哥Haskell编译器,版本7.4.1,第2阶段由GHC版本7.4.1启动

2 个答案:

答案 0 :(得分:11)

这是完全懒惰的“优化”咬你。当它正常工作时,它可以提供运行时间的渐近改进。当它工作错误时......会发生这种情况。

完全惰性变换将常量移出绑定到封闭范围的常量。在这种情况下,它会获取[1..(1073741824-1)]常量,并将其移动到封闭范围。但是,这是完全错误的。它导致它在两个调用之间共享,这意味着它无法在第一次有效地流式传输。

除了没有-O2编译外,没有可靠的方法可以打败完整的懒惰转换。

答案 1 :(得分:3)

卡尔解释的原因非常好,我不认为我可以帮助你了。

但我可以告诉你如何解决这个问题。

首先,您g的确总结为1073741823并添加f a

有一个简单的公式可以将数字从1加到n而没有那么多的加法(据说Gauss在primary-school找到了它):

sumUp :: (Integral a) => a -> a
sumUp n = n * (n+1) `div` 2

用这个你可以写

f x = x*x
g a = sumUp (1073741824-1) + f a
main = do putStrLn $ show $ foldl' (+) 0 $ map g [0,1]

备注

你可以看一下链接,直观地看出为什么这样做或者试着自己找到证据 - 使用归纳法很容易:D