【发布时间】:2017-02-20 17:30:10
【问题描述】:
我想测试一个小型测试程序的内存使用情况。程序如下:
import Data.List as L
main :: IO
main = print $ L.find (==100000) [1..1000000000]
它找到第 100000 个值。我希望看到这个程序只会将内存用于 100000 个值。当我通过+RTS -hy 生成内存配置文件时,我得到了一个空配置文件:
我很惊讶并认为GHC 可能比我想象的更有效率。也许这些值永远不必加载到内存中,因为结果已经可以确定。
所以我尝试了一个需要所有值直到第 100000 个的问题:
main = print $ takeUntil (==100000) [1..]
takeUntil :: (Int -> Bool) -> [Int] -> [Int]
takeUntil _ [] = []
takeUntil f (x:xs) = if f x
then []
else x : takeUntil f xs
仍然,内存配置文件是空的。我认为这是因为 GHC 正在对这个程序进行某种融合,其中的值由 takeUntil 计算并同时打印出来,这样它们就可以立即被垃圾回收。
所以我写了另一个程序,需要takeUntil 的结果留在内存中:
main = let taken = takeUntil (==100000) [1..]
mapped = L.map (+1) taken
in print taken >> print mapped
这给出了我期望的内存配置文件: 我想看看如果我只请求一半的样本,程序会使用多少内存:
main = let taken = takeUntil (==50000) [1..]
mapped = L.map (+1) taken
in print taken >> print mapped
我生成了内存配置文件,但它又是空的!
当我要求更多样品时:
main = let taken = takeUntil (==200000) [1..]
mapped = L.map (+1) taken
in print taken >> print mapped
有人可以解释这种行为吗?
代码位于名为Main.hs 的文件中。我通过ghc Main.hs -O2 -rtsopts -prof 编译。我通过运行+RTS -hy 构建内存配置文件,并使用hp2ps -e8in -c 和ps2pdf 生成pdf。
【问题讨论】:
-
默认的堆配置文件频率是每 0.1 秒,所以也许你的空配置文件只是因为程序没有运行足够长的时间。您可以使用
-i<sec>RTS 选项调整堆配置文件频率。 -
@ReidBarton 谢谢,就是这样!
-
@ReidBarton 这应该是一个答案。
标签: haskell lazy-evaluation heap-memory