堆满了 PINNED

Heap is full of PINNED

我有一个小程序,它具有合理的最大驻留但线性分配。起初,我认为应该是 cons 单元或 I#,但是 运行 带有 -p -hc 的程序显示堆被 PINNED 淹没。有谁明白原因 and/or 可以提出改进建议吗?

节目

-- task27.hs
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad
import Control.Monad.ST
import Control.Exception 
import System.Random
import Data.Functor

import qualified Data.Vector.Generic.Mutable as V
import qualified Data.Vector.Unboxed as U

m = 120

task27 :: [Int] -> (Int, Int)
task27 l = runST $ do 
    r <- V.replicate m 0 :: ST s (U.MVector s Int)

    let go []     = return (1,2)
        go (a:as) = do
          let p = a `mod` m
          cur_lead <- r `V.read` p
          when (a > cur_lead) (V.write r p a)
          go as
    go l

randTest :: 
  Int -> -- Length of random testing sequence
  IO ()
randTest n =
  newStdGen <&>
  randoms <&> 
  take n <&> 
  task27 >>=
  print

main = randTest 1000000

我的package.yaml:

name: task27
dependencies:
  - base == 4.*
  - vector
  - random

executables:
  task27:
    main: task27.hs
    ghc-options: -O2

我的cabal.project.local:

profiling: True

cabal -v0 run task27 -- +RTS -p -hc && hp2ps -e8in -c task27.hp 得到了这个:

我试着到处加刘海,但似乎没有用。

正如@WillemVanOnsem 所说,在 GHC 术语中,35kB 驻留空间是微不足道的。无论您遇到什么性能问题,都与这一小块固定内存无关。最初,我说这可能是 Vector,但那是错误的。 Data.Text 使用固定内存,但 Data.Vector 不使用。这段 PINNED 内存看起来实际上来自 运行 时间系统本身,因此您可以忽略它(见下文)。

在GHC代码中,"total allocation"是处理的一种度量。 GHC 程序是一个分配引擎。如果它没有分配,它可能没有做任何事情(极少数例外)。因此,如果您希望您的算法在 O(n) 时间 中达到 运行,那么它的总分配也将是 O(n),通常是千兆字节。

关于 "rare exceptions",如果积极优化允许使用完全未装箱的值进行计算,则 GHC 程序可以 运行 恒定 "total allocation" 但非恒定时间。所以,例如:

main = print (sum [1..10000000] :: Int)

运行s 在常量总分配中(例如,在堆上分配 50kB),因为 Ints 可以拆箱。为了比较,

main = print (sum [1..10000000] :: Integer)

运行s 总分配为 O(n)(例如,在堆上分配了 320MB)。顺便说一下,尝试分析最后一个程序(并增加计数,直到 运行 足够长以生成几秒钟的分析数据)。您会看到它使用与您的程序相同数量的 PINNED 内存,并且该数量并没有真正随着上限而变化。所以,这只是 运行 时间系统开销。

回到你的例子...如果你担心性能,罪魁祸首可能是 System.Random。这是一个 EXTREMELY 慢速随机数生成器。如果我 运行 你的程序 n = 10000000,它需要 4 秒。如果我用简单的 LCG 替换随机数生成器:

randoms :: Word32 -> [Word32]
randoms seed = tail $ iterate lcg seed
  where lcg x = (a * x + c)
        a = 1664525
        c = 1013904223

它在 0.2 秒内 运行 秒,所以快了 20 倍。