我得到了这个函数,它解析一个字符串,其中包含用反斜杠转义的特殊字符。
parseEscapedString :: Parser String
parseEscapedString =
char '\''
*> many'
( notChar '\'' >>= \case
'\\' -> anyChar
c -> pure c
)
<* char '\''
我使用的是attoparsec
,确切地说是Data.Attoparsec.ByteString.Char8
虽然这个函数可以按预期工作,但在解析大量字符串时,它会占用大量内存。
我有一个大小为850Mb的文件,其中包含我想要解析的内容,其中一部分是这些字符串。但是当我尝试解析这个文件时,程序需要大约10Gb的内存才能成功完成(-O2
)。
当使用-prof
编译并使用+RTS -hc
运行时,堆使用统计数据显示,主解析函数略微增加了内存使用,这是分配解析结构所预期的,然而,最大的内存使用来自函数parseEscapedString
,绝对是巨大的。
这是attoparsec
或bytestring
的内存泄漏,还是我搞砸了什么?
(这是保存40秒后运行,但当编译与-prof
的程序是相当慢,运行约5分钟前被杀死,因为内存不足(使用约20GB),这导致统计数据没有被保存,但我不认为有任何区别,以第一个40秒。
1条答案
按热度按时间bakd9h0s1#
它可能只是
String
本身的存储。回想一下,GHC
String
是一个链表表示,结果是每个字符“节点”需要24个字节(每个节点由三个64位四元组组成::
构造函数的信息指针、Char
的指针和下一个节点的指针)。假设850MB文件的50%由字符串组成,解析它将需要0.50*850*24=10200
兆字节的驻留字符串存储。这与解析器的细节无关。您将在如下解析器中看到相同的问题:最简单的解决方法是解析为严格的
Text
或ByteString
表示。因为你只处理Char8
字符串,所以ByteString
表示是有意义的。下面的解析器应该可以工作。你仍然需要相当于你的字符串的ByteString
总需求的驻留存储空间。但是它应该比普通的String
表示少24倍的存储: