我正在使用XML -conduit的流接口https://hackage.haskell.org/package/xml-conduit-1.8.0/docs/Text-XML-Stream-Parse.html#v:parseBytes解析一些相当大的xml文件,但是我看到了内存的积累(这里是一个小的测试文件):

排名靠前的用户是:

实际数据不应该占用那么多堆-如果我序列化并重新读取,驻留内存使用的是千字节,而不是这里的兆字节。
我用来重现这一点的最小例子是:
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Monad
import Control.Monad.IO.Class
import Data.Conduit
import Data.Conduit.Binary (sourceFile)
import qualified Data.Conduit.List as CL
import Data.Text (Text)
import Text.XML.Stream.Parse
type Y = [(Text, Text)]
main :: IO ()
main = do
res1 <- runConduitRes $
sourceFile "test.xml"
.| Text.XML.Stream.Parse.parseBytes def
.| parseMain
.| CL.foldM get []
print res1
get :: (MonadIO m, Show a) => [a] -> [a] -> m [a]
get acc !vals = do
liftIO $! print vals -- this oughta force it?
return $! take 1 vals ++ acc
parseMain = void $ tagIgnoreAttrs "Period" parseDetails
parseDetails = many parseParam >>= yield
parseParam = tag' "param" parseParamAttrs $ \idAttr -> do
value <- content
return (idAttr, value)
parseParamAttrs = do
idAttr <- requireAttr "id"
attr "name"
return idAttr发布于 2019-03-29 20:38:53
如果我将get更改为只返回["hi"]或其他什么,我就不会得到积压。因此,返回的文本似乎保留了对它们所在的较大文本的一些引用(例如,零拷贝切片,参见。注释在https://hackage.haskell.org/package/text-0.11.2.0/docs/Data-Text.html#g:18 ),所以文本的其余部分不能被垃圾收集,即使我们只使用了很小的部分。
我们的解决方法是在任何我们想要生成的属性上使用Data.Text.copy:
someattr <- requireAttr "n"
yield (T.copy someattr)这让我们可以使用几乎不变的内存进行解析。
(如果我们想节省更多的内存,我们可以考虑使用https://markkarpov.com/post/short-bs-and-text.html#shorttext。)
https://stackoverflow.com/questions/55417620
复制相似问题