为什么在优化并多次调用此功能后会消耗内存?

Tru*_*man 7 haskell

我有一个函数,可以从十亿个整数列表中筛选出一些值。如果仅调用一次,则内存使用率几乎是恒定的,但是如果调用两次,则将占用超过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]

但是,它会在完成之前耗尽内存。