如果我使用-Xmx8G将JAVA VM大小设置为8G,那么我有一个工作的ANTLR4编译器,适用于高达~300Mb的文件。但是,较大的文件会使解析器/编译器因HEAP内存不足而崩溃。我被建议在ANTLR4进程之外检查我的代码以获取内存消耗。 (下面的数据)我正在使用令牌工厂和unbufferedChar和令牌流。
我正在使用的一个策略是测试INPUT文件/流的大小(如果可知的话),就我的情况而言。如果文件很小,则使用我的顶级规则进行解析,该规则生成一个很大的解析树,但适用于小文件。
如果文件大于任意阈值,我尝试通过选择子规则将解析分成块。因此,对于小文件,我解析规则patFile(现有的工作代码),对于大型文件,我正在通过解析子规则“patFileHeader”来解决问题,然后解析规则“bigPatternRec”,它取代了“pattern +”部分。以前的规则。 通过这种方式,我的期望是我可以控制读取多少令牌流。
目前这看起来很有希望,但我看到控制ANTLR4在处理标头时解析了多少问题。我可能有一个语法规则,导致patFileHeader在退出之前使用所有可用的输入标记。其他情况似乎有效,但我还在测试。我只是不确定这种解决“大文件”解析的方法是否可行。
SMALL文件示例语法:
patFile : patFileHeader patterns+
// {System.out.println("parser encountered patFile");}
;
patFileHeader : SpecialDirective? includes* gbl_directives* patdef
;
patterns : patdata+ patEnd
// {System.out.println("parser encountered patterns");}
;
bigPatternRec : patdata
| patEnd
;
...
在我的小文件的情况下,我用:
创建解析树 parser = new myparser(tokens);
tree = parser.patFile(); // rule that parses to EOF
walker=walk(mylisteners,tree);
将整个文件解析为EOF。
对于较大的文件,我考虑了以下技术:
// Process the first few lines of the file
tree = parser.patFileHeader(); // sub rule that does not parse to EOF
walker=walk(mylisteners,tree);
//
// Process remaining lines one line/record at a time
//
while( inFile.available() ) {
parser = new myParser(tokens);
tree = parser.bigPatternRec();
walker=walk(mylisteners,tree);
}
在回应我描述行为的建议时,我在处理项目期间在“整个文件”上生成了JVMonitor的屏幕截图。 对我来说有一点感兴趣的是三个上下文集~398Mb。在我的语法中,vec是vecdata的一个组件,因此看起来某些上下文数据正在被复制。我可以玩那个。 char []条目可能是我在ANTLR4之外的代码。我必须禁用我的监听器并运行以生成解析树,而不管我的代码是否有效。我做其他消耗内存(MappedByteBuffers)的东西,用于输出上的高速文件I / O,这将有助于超过8Gb图像。
有趣的是,如果我打破调用并且只是处理子规则,内存映像会发生什么。内存消耗大约为全尺寸的10%,在这种情况下,ANTLR4对象甚至不在雷达上。