如何使文件夹消耗恒定的内存?

时间:2019-02-20 10:58:14

标签: haskell memory-management fold

我们定义以下数据类型Stupid

import qualified Data.Vector as V
import Data.List (foldl')
data Stupid = Stupid {content::V.Vector Int, ul::Int} deriving Show

现在我有两个略有不同的代码。

foldl' (\acc x->Stupid{content=(content acc) V.// [(x,x+123)],ul=1}) (Stupid {content=V.replicate 10000 10,ul=1}) $ take 100000 $ cycle [0..9999]

需要持续的内存(〜100M),而

foldl' (\acc x->Stupid{content=(content acc) V.// [(x,x+123)],ul=ul acc}) (Stupid {content=V.replicate 10000 10,ul=1}) $ take 100000 $ cycle [0..9999]

占用大量内存(〜8G)。

从理论上讲,尽管在两种情况下都不需要处理,但当前Stupid对象只需要一个副本。我不明白为什么要访问和记录ul acc时,内存消耗会有如此大的差异。

如果我需要访问ul acc,有人可以解释为什么会发生这种情况,并给出解决方案以保持内存不变吗?谢谢。

注意:我知道我可以批量替换向量,该脚本仅用于演示目的,因此请不要修改该部分。

1 个答案:

答案 0 :(得分:1)

我会尝试强制使用Stupid的字段,看看是否有帮助。

let f acc x = c `seq` a `seq` Stupid{content=c,ul=a}
       where
       c = content acc V.// [(x,x+123)]
       a = ul acc
in foldl' f (Stupid {content=V.replicate 10000 10,ul=1}) $
   take 100000 $
   cycle [0..9999]

这几乎等同于强制使用函数的参数:

foldl' (\acc x -> acc `seq` x `seq` 
        Stupid{content=(content acc) V.// [(x,x+123)],ul=ul acc})
   (Stupid {content=V.replicate 10000 10,ul=1}) $ take 100000 $ cycle [0..9999]

(如果喜欢的话,也可以用爆炸样式来写。)

另一种更具侵略性的选择是在Stupid构造函数的定义中使用严格性注释。

data ... = Stupid { content = ! someType , ul :: ! someOtherType }

这将始终在整个程序中强制使用这些字段。