C# 为什么在使用ANTLR生成解析器树时会出现OutOfMemoryException?
我构建了一个“simples”语法来解释一个看起来像json(或xml)的文件。但是,当我试图解析文件并在树上导航时,我得到了一个C# 为什么在使用ANTLR生成解析器树时会出现OutOfMemoryException?,c#,antlr,C#,Antlr,我构建了一个“simples”语法来解释一个看起来像json(或xml)的文件。但是,当我试图解析文件并在树上导航时,我得到了一个System.OutOfMemoryException 输入文件只有108MB,但包含近500万行 以下是该文件的示例: ( :field ("ObjectName" :field ( :field ("{6BF621F9-A0E2-49BB-A86B-3DE4750954F4}") :field
System.OutOfMemoryException
输入文件只有108MB,但包含近500万行
以下是该文件的示例:
(
:field ("ObjectName"
:field (
:field ("{6BF621F9-A0E2-49BB-A86B-3DE4750954F4}")
:field (Value)
:field (Value)
:field (
:Time ("Sun Jan 26 10:08:33 2014")
:last_modified_utc (1390730913)
:By ("Some text")
:From (localhost)
)
:field ("text/text")
:field (false)
:field (false)
)
:field ()
:field ()
:field ()
:field (0)
:field (true)
:field (true)
)
.
.
.
.
.
)
遵循语法:
grammar Objects;
/*
* Parser Rules
*/
compileUnit
: obj
;
obj
: OPEN ID? (field)* CLOSE
;
field
: ':'(ID)? obj
;
/*
* Lexer Rules
*/
OPEN
: '('
;
CLOSE
: ')'
;
ID
: (ALPHA | ALPHA_IN_STRING)
;
fragment
INT_ID
: ('0'..'9')
;
fragment
ALPHA_EACH
: 'A'..'Z' | 'a'..'z' | '_' | INT_ID | '-' | '.' | '@'
;
fragment
ALPHA
: (ALPHA_EACH)+
;
fragment
ALPHA_IN_STRING
: ('"' ( ~[\r\n] )+ '"')
;
WS
// : ' ' -> channel(HIDDEN)
: [ \t\r\n]+ -> skip // skip spaces, tabs, newlines
;
和解析器:
var input = new Antlr4.Runtime.AntlrInputStream(text);
var lexer = new ObjectsLexer(input);
var tokens = new Antlr4.Runtime.CommonTokenStream(lexer);
var parser = new ObjectsParser(tokens);
// Context for the compileUnit rule
// ERROR: Here I got the error. When start the to build the tree for compileUnit rule
var ctx = parser.compileUnit();
// The following line is not executed
new ObjectsVisitor().Visit(ctx);
在错误线上,我意识到内存呈指数增长。- 如果输入是UTF-8编码的,并且主要使用ASCII字符,则转换为UTF-16将需要大约216MB
- 每个令牌使用至少48字节的内存
- 出现在解析树中的每个令牌使用至少20字节的内存(除了44字节)
- 解析树中的每个规则节点至少使用36字节的内存。如果规则有任何子项,则最小值为68字节
- 输入:216MB
- 约2800万代币:~1281MB
- 解析树中约1400万个终端节点:~267MB
- 约470万解析树节点:~308MB
这是超过2GB的内存,并且不计算与运行时或由ANTLR内部构造的动态DFA缓存相关的任何开销。显然,您需要将应用程序作为64位进程运行,或者减少输入的大小。如果我有一个大的XML文件,比如500万行,那么ANTLR将不是读取/解释它的最佳工具,是吗?在这种情况下,我是否应该在不使用ANTLR的情况下将某些内容作为一个部分?是否有任何方法可以清除缓存?我知道这并不理想,但内存不足也不理想:-(