5

多くのレベルを持つ巨大なディレクトリで、XSLT2 を使用して XML ファイルを変換したいと考えています。100 万以上のファイルがあり、各ファイルは 4 ~ 10 kB です。しばらくすると、常に java.lang.OutOfMemoryError: Java heap space を受け取ります。

私のコマンドは次のとおりです。 java -Xmx3072M -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=512M ...

-Xmx にメモリを追加するのは良い解決策ではありません。

ここに私のコードがあります:

for (File file : dir.listFiles()) {
    if (file.isDirectory()) {
        pushDocuments(file);
    } else {
        indexFiles.index(file);
    }
}

public void index(File file) {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

    try {
        xslTransformer.xslTransform(outputStream, file);
        outputStream.flush();
        outputStream.close();
    } catch (IOException e) {
        System.err.println(e.toString());
    }
}

net.sf.saxon.s9api による XSLT 変換

public void xslTransform(ByteArrayOutputStream outputStream, File xmlFile) {
    try {
        XdmNode source = proc.newDocumentBuilder().build(new StreamSource(xmlFile));
        Serializer out = proc.newSerializer();
        out.setOutputStream(outputStream);
        transformer.setInitialContextNode(source);
        transformer.setDestination(out);
        transformer.transform();

        out.close();
    } catch (SaxonApiException e) {
        System.err.println(e.toString());
    }
}
4

4 に答える 4

5

Saxon s9api インターフェースに関する私の通常の推奨事項は、XsltExecutable オブジェクトを再利用することですが、変換ごとに新しい XsltTransformer を作成することです。XsltTransformer は、読み取ったドキュメントが再度必要になった場合に備えてキャッシュしますが、これはこの場合は望ましくありません。

xsltTransformer.getUnderlyingController().clearDocumentPool()別の方法として、各変換後に呼び出すこともできます。

(注意してください、saxonica.plan.io で Saxon に関する質問をすることができます。これにより、[Saxonica] がそれらに気づき、回答する可能性が高くなります。また、ここで質問して「saxon」のタグを付けることもできます。製品固有のタグを付けずに StackOverflow で質問すると、誰かが質問に気付くかどうかは完全に行き当たりばったりです。)

于 2013-11-04T10:10:43.647 に答える
0

XSLT 中に読み取られた XML チャンクをキャッシュするために ThreadLocalMap を使用する javax.xml.transform パッケージから発生した同様の問題がありました。新しいスレッドが終了したときに ThreadLocalMap がクリアされるように、XSLT を独自のスレッドに外部委託する必要がありました。これにより、メモリが解放されました。ここを参照してください: https://www.ahoi-it.de/ahoi/news/java-xslt-memory-leak/1446

于 2013-11-13T10:31:47.270 に答える
0

メモリリークがないことを確認します。一度に 1 つしか処理していないため、ファイルの数は重要ではありません。最大のファイルを処理できる限り、すべてのファイルを処理できるはずです。

jstat -gc {pid} 10sプログラムの実行中に実行して、メモリリークを探すことをお勧めします。探す必要があるのは、フル GC 後のメモリのサイズです。これが増加している場合は、VisualVM メモリ プロファイラーを使用してその理由を突き止めてください。またはjmap -histo:live {pid} | head -20ヒントに使用します。

メモリが増加していない場合は、メモリ不足を引き起こしているファイルがあります。これは、a) ファイルが他のファイルよりもはるかに大きいか、またはより多くのメモリを使用している、b) ライブラリでバグを引き起こしているためです。

于 2013-11-04T09:00:09.177 に答える
0

これを試してみてください

String[] files = dir.list();
for (String fileName : files) {
    File file = new File(fileName);
    if (file.isDirectory()) {
        pushDocuments(file);
    } else {
        indexFiles.index(file);
    }
}
于 2013-11-04T09:00:22.383 に答える