2

ANTLRで大きなlog(30MByte)ファイルを解析しようとしています。
しかし、OOMでクラッシュするか、パーサーが機能するにつれて非常に遅くなりました。

私が知っていたように、
1。レクサーはテキストとyeidsトークンをスキャンします
2.パーサーは与えられたルールでトークンを消費します

すでに消費されているトークンはgcで収集する必要がありますが、そうではないようです。
何が問題なのか教えていただけますか?(文法またはコード)

最小化された文法とコードは以下のとおりです

LogParser.g

grammar LogParser;

options {
  language = Java;
}

rule returns [Line result]
  :
  stamp WS text NL 
                   {
                    result = new Line();
                    result.setStamp(Integer.parseInt($stamp.text));
                    result.setText($text.text + $NL.text);
                   }
  ;

stamp
  :
  DIGIT+
  ;

text
  :
  CHAR+
  ;

DIGIT
  :
  '0'..'9'
  ;

CHAR
  :
  'A'..'Z'
  ;

WS
  :
  ' '
  ;

NL
  :
  '\r'? '\n'
  ;

Test.java

import java.io.IOException;

import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;

public class Test {

    public static void main(String[] args) {
        try {
            CharStream input = new ANTLRFileStream("aaa.txt");
            LogParserLexer lexer = new LogParserLexer(input);
            CommonTokenStream tokenStream = new CommonTokenStream(lexer);
            LogParserParser parser = new LogParserParser(tokenStream);

            int count = 0;

            while (true) {
                count++;
                parser.rule();
                parser.setBacktrackingLevel(0);
                if (0 == count % 1000)
                    System.out.println(count);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (RecognitionException e) {
            e.printStackTrace();
        }
    }
}

Line.java

public class Line {
    private Integer stamp;
    private String text;

    public Integer getStamp() {
        return stamp;
    }

    public void setStamp(Integer stamp) {
        this.stamp = stamp;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    @Override
    public String toString() {
        return String.format("%010d %s", stamp, text);
    }

}

aaa.txt、ランダムに生成されたコンテンツ。そのサイズは約30メガバイトです。

0925489881 BIWRSAZLQTOGJUAVTRWV
0182726517 WWVNRKGGXPKPYBDIVUII
1188747525 NZONXSYIWHMMOLTVPKVC
1605284429 RRLYHBBQKLFDLTRHWCTK
1842597100 UFQNIADNPHQYTEEJDKQN
0338698771 PLFZMKAGLGWTHZXNNZEU
1971850686 TDGYOCGOMNZUFNGOXLPM
1686341878 NTYUXJSVQYXTBZAFLJJD
0849759139 YRXZSVWSZDBJPSNSWNJH
:
:
:

サンプルジェネレータ

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;

public class EntryPoint {

    /**
     * @param args
     */
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            int size = 20;
            String formatLength = Integer.toString(Integer.MAX_VALUE);
            String pattern = "%0" + formatLength.length() + "d ";

            Random random = new Random();
            File file = new File("aaa.txt");
            fw = new FileWriter(file);
            while (true) {
                int nextInt = random.nextInt(Integer.MAX_VALUE);

                StringBuilder sb = new StringBuilder();
                sb.append(String.format(pattern, nextInt));
                for (int i = 0; i < size; i++) {
                    sb.append((char) ('A' + random.nextInt(26)));
                }

                fw.append(sb);
                fw.append(System.getProperty("line.separator"));

                if (file.length() > 30000000)
                    break;
            }

            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

JavaSE-1.6(jre6)、Windows 7 64vmarg"-Xmx256M"での結果

85000
86000
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.antlr.runtime.Lexer.emit(Lexer.java:160)
at org.antlr.runtime.Lexer.nextToken(Lexer.java:91)
at org.antlr.runtime.BufferedTokenStream.fetch(BufferedTokenStream.java:133)
at org.antlr.runtime.BufferedTokenStream.sync(BufferedTokenStream.java:127)
at org.antlr.runtime.CommonTokenStream.consume(CommonTokenStream.java:67)
at org.antlr.runtime.BaseRecognizer.match(BaseRecognizer.java:106)
at LogParserParser.text(LogParserParser.java:190)
at LogParserParser.rule(LogParserParser.java:65)
at Test.main(Test.java:21)
4

1 に答える 1

1

UnbufferedTokenStreamがあなたが望むものだと思います。charストリームのバッファリングも解除する必要があるかもしれません。

于 2012-12-09T17:47:29.023 に答える