我有一个函数,可以从十亿个整数列表中筛选出一些值。如果仅调用一次,则内存使用率几乎是恒定的,但是如果调用两次,则将占用超过8 gig的内存。这似乎仅在使用-O2进行优化以及使用元组过滤列表时才发生。
我从代码中删除了这个测试用例,该代码做了一些更有用,更复杂的事情,但是函数findLgMod3演示了此问题,而函数findLgMod3Simp却没有。这些函数返回的最大值<= 10亿,即输入的3 mod。当然,有更好的方法可以做到这一点,但是它们不会证明这个问题。
我正在使用ghc版本8.6.5进行编译:
ghc -O2-动态map_mem_prob.hs
注释掉的代码显示了使用和不使用过多内存的变体。
编写的代码在未经优化或使用-O1进行编译时将占用很少的内存,因此我认为这与使用-O2优化并使用元组来过滤列表有关,但是我不知道这是否是预期的行为,是否可以,如何重新处理该函数,使其仍然可以使用元组进行过滤,但不会出现此问题。
findLgMod3 :: Int -> Int
findLgMod3 modVal = maxAns
where
maxAns = if null allAns then 0 else last allAns
allAns = (map snd . filter (\(three, val) -> three == (val `rem` modVal))
. zip (repeat 3)) [1..1000000000]
findLgMod3Simp :: Int -> Int
findLgMod3Simp modVal = maxAns
where
maxAns = if null allAns then 0 else last allAns
allAns = (filter ((== 3) . (`rem` modVal))) [1..1000000000]
main :: IO ()
main = do
let val1 = 600000000
val2 = 700000000
let answers = map findLgMod3 [val1, val2] -- This blows up memory.
-- let answers = [findLgMod3 val1, findLgMod3 val2] -- This blows up memory.
-- let answer1 = findLgMod3 val1 -- This blows up memory.
-- answer2 = findLgMod3 val2
-- answers = answer1 + answer2
-- let answers = map findLgMod3Simp [val1, val2] -- This doesn't blow up memory.
-- let answers = map findLgMod3 [val1] -- This doesn't blow up memory.
-- let answers = [findLgMod3 val1] -- This doesn't blow up memory.
-- let answer1 = findLgMod3Simp val1 -- This doesn't blow up memory.
-- answer2 = findLgMod3Simp val2
-- answers = [answer1, answer2]
putStrLn $ "Answers: " ++ show answers
Run Code Online (Sandbox Code Playgroud)
该程序的输出应为:
答案:[600000003,700000003]
但是,它会在完成之前耗尽内存。