gpt4 book ai didi

haskell - 过多的垃圾收集(和内存使用?)

转载 作者:行者123 更新时间:2023-12-02 16:40:04 24 4
gpt4 key购买 nike

我发现了一个库的一小部分似乎包含内存泄漏。下面的代码尽可能小,但仍然产生与真实代码相同的结果。

import System.Random
import Control.Monad.State
import Control.Monad.Loops
import Control.DeepSeq
import Data.Int (Int64)
import qualified Data.Vector.Unboxed as U

vecLen = 2048

main = flip evalStateT (mkStdGen 13) $ do
let k = 64
cs <- replicateM k transform
let sizeCs = k*2*7*vecLen*8 -- 64 samples, 2 elts per list, each of len 7*vecLen, 8 bytes per Int64
(force cs) `seq` lift $ putStr $ "Expected to use ~ " ++ (show ((fromIntegral sizeCs) / 1000000 :: Double)) ++ " MB of memory\n"

transform :: (Monad m, RandomGen g)
=> StateT g m [U.Vector Int64]
transform = do
e <- liftM ((U.map round) . (uncurry (U.++)) . U.unzip) $ U.replicateM (vecLen `div` 2) sample
c1 <- U.replicateM (7*vecLen) $ state random
return [U.concat $ replicate 7 e, c1]

sample :: (RandomGen g, Monad m) => StateT g m (Double, Double)
sample = do
let genUVs = liftM2 (,) (state $ randomR (-1,1)) (state $ randomR (-1,1))
-- memory usage drops and productivity increases to about 58% if I set the guard to "False" (the real code needs a guard here)
uvGuard (u,v) = u+v >= 2 -- False --
(u,v) <- iterateWhile uvGuard genUVs
return (u, v)

删除更多代码可以显着提高性能,无论是在内存使用/GC、时间还是两者方面。但是,我需要计算上面的代码,所以真正的代码再简单不过了。例如,如果我让 e 和 c1 都从 sample 获取值,则代码使用 27 MB 内存,并在 GC 中花费 9% 的运行时间。如果我让 e 和 c1 都使用状态随机,我会使用大约 400MB 的内存,并且只在 GC 上花费 32% 的运行时间。

主要参数是vecLen,我确实需要8192左右。为了加快分析速度,我用vecLen=2048生成了下面的所有结果,但问题是随着 vecLen 的增加,情况会变得更糟。

编译

ghc test -rtsopts

我得到:

> ./test +RTS -sstderr
Working...
Expected to use ~ 14.680064 MB of memory
Done
3,961,219,208 bytes allocated in the heap
2,409,953,720 bytes copied during GC
383,698,504 bytes maximum residency (17 sample(s))
3,214,456 bytes maximum slop
869 MB total memory in use (0 MB lost due to fragmentation)

Tot time (elapsed) Avg pause Max pause
Gen 0 7002 colls, 0 par 1.33s 1.32s 0.0002s 0.0034s
Gen 1 17 colls, 0 par 1.60s 1.84s 0.1080s 0.5426s

INIT time 0.00s ( 0.00s elapsed)
MUT time 2.08s ( 2.12s elapsed)
GC time 2.93s ( 3.16s elapsed)
EXIT time 0.00s ( 0.03s elapsed)
Total time 5.01s ( 5.30s elapsed)

%GC time 58.5% (59.5% elapsed)

Alloc rate 1,904,312,376 bytes per MUT second

Productivity 41.5% of total user, 39.2% of total elapsed


real 0m5.306s
user 0m5.008s
sys 0m0.252s

使用 -p 或 -h* 进行分析并不能透露太多信息,至少对我来说是这样。

但是,线程作用域很有趣:threadscope

在我看来,我好像在破坏堆,所以 GC 正在发生,堆大小加倍。事实上,当我使用 -H4000M 运行时,threadscope 看起来稍微更均匀(更少的双倍工作,双倍 GC),但我仍然花费大约 60% 的总体运行时间来执行 GC。使用 -O2 编译情况更糟,超过 70% 的运行时间都花在 GC 上。

问题:1. 为什么GC运行这么多?2. 我的堆使用量是否出乎意料地大?如果是这样,为什么?

对于问题 2,我意识到堆使用量可能会超出我的“预期”内存使用量,甚至超出很多。但800MB对我来说似乎有点太大了。 (这就是我应该查看的数字吗?)

最佳答案

为了解决这样的问题,我通常会在我认为可能有大量分配的地方使用 SCC 编译指示来开始代码。在这种情况下,我怀疑 transform 中的 ec1 以及 sample< 中的 genUVs/,

...

transform :: (Monad m, RandomGen g)
=> StateT g m [U.Vector Int64]
transform = do
e <- {-# SCC e #-} liftM (U.map round . uncurry (U.++) . U.unzip) $ U.replicateM (vecLen `div` 2) sample
c1 <- {-# SCC c1 #-} U.replicateM (7*vecLen) $ state random
return [U.concat $ replicate 7 e, c1]

sample :: (RandomGen g, Monad m) => StateT g m (Double, Double)
sample = do
let genUVs = {-# SCC genUVs #-} liftM2 (,) (state $ randomR (-1,1)) (state $ randomR (-1,1))
-- memory usage drops and productivity increases to about 58% if I set the guard to "False" (the real code needs a guard here)
uvGuard (u,v) = u+v >= 2 -- False --
(u,v) <- iterateWhile uvGuard genUVs
return $ (u, v)

我们首先使用 -hy 查看相关对象的类型。这揭示了许多不同的类型,包括IntegerInt32StdGenInt(, )。使用-hc我们可以确定几乎所有这些值都分配在transformc1中。 -hr 证实了这一点,它告诉我们谁持有对这些对象的引用(从而防止它们被垃圾收集)。我们可以通过使用 -hrc1 -hy 检查它保留的对象类型来进一步确认 c1 是罪魁祸首(假设我们用 {-# 注解它) SCC c1 #-})。

事实上,c1 保留了如此多的对象,这表明它没有在我们希望的时候被评估。虽然在评估之后,c1 是一个相当短的向量,但在评估之前,它需要数千个随机种子、关联的闭包,以及可能的许多其他对象。

Deepseqing c1 使 GC 时间从 59% 减少到 23%,并将内存消耗减少一个数量级。这就是 transform 中的终端 return 转变成,

deepseq c1 $ return [U.concat $ replicate 7 e, c1]

此后,配置文件看起来相当合理,最大的空间用户在 transform 中分配了大约 10MB 的 ARR_WORDS(如预期),后面是一些元组,可能来自 genUVs.

关于haskell - 过多的垃圾收集(和内存使用?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19164151/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com