使用文本键入的Hashtables时,内存泄漏



我正在使用Hashtable软件包在Haskell中编写贝叶斯天真分类器。但是,在处理较大的语料库时,我会有大量的内存泄漏可能是由于大量价值更新引起的。当加载已经指定的单词计数时,它需要大约2GB的RAM,但是当计数从Corpus 8GB RAM发生的单词发生时,这还不够,仅崩溃。我该如何防止它?代码计数单词看起来像:

chars :: T.Text
chars = "qwertyuiopasdfghjklzxcvbnmęóąśłżźćńt "
el :: Char -> T.Text -> Bool
el = T.any . (==)
preprocess :: T.Text -> [T.Text]
preprocess !line = T.words . T.map check . T.toLower $ line
             where check !x = if x `el` chars then x else ' '
loop :: Handle -> Corpus -> IO ()
loop hdl dic =
    hIsEOF hdl >>= x -> if x
        then return ()
        else do
          cl:dat <- preprocess <$> TIO.hGetLine hdl
          let ins !word =
                        if (T.length word <= 20) && (T.length word >= 4)
                          then (H.lookup dic word >>=
                                mprob -> case mprob of
                                   Just (SexProbs m f) -> do
                                     H.delete dic word
                                     H.insert dic word $ if cl == "m" then SexProbs (m+1) f else SexProbs m (f+1)
                                   Nothing -> H.insert dic word $ if cl == "m" then SexProbs 1 0 else SexProbs 0 1)
                          else return ()
          mapM_ ins dat
          loop hdl dic

分析表明,最大的分配来源是预处理和循环,但我不知道如何减少内存使用。

原因似乎是您的SexProbs数据类型。它可能是用懒惰的字段定义的(假设对计数器的Int):

data SexProbs = SexProbs Int Int

使用SexProbs (m+1) n构建一个新值评估加法,而是将thunk放在堆内存中。这些积累并导致空间泄漏。

为了避免这种情况,请用seq 对计数器进行强制评估
let m' = m+1 in m' `seq` SexProbs m' n

或更改您的类型定义以使用严格字段:

data SexProbs = SexProbs !Int !Int