5

我想使用 XSLT2 转换 XML 文件,在一个有很多级别的巨大目录中。有超过100万个文件,每个文件4到10 kB。过了一会儿,我总是收到 java.lang.OutOfMemoryError: Java heap space。

我的命令是:java -Xmx3072M -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEna bled -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 上向撒克逊人提问,这让我们 [Saxonica] 很有可能会注意到他们并回答他们。您也可以在这里问他们并将他们标记为“撒克逊人”,这意味着我们将可能会在某个时候回答这个问题,但并不总是立即回答。如果您在 StackOverflow 上询问没有特定于产品的标签,那么是否有人会注意到这个问题完全是偶然的。)

于 2013-11-04T10:10:43.647 回答
0

我有一个来自 javax.xml.transform 包的类似问题,该包使用 ThreadLocalMap 缓存在 XSLT 期间读取的 XML 块。我不得不将 XSLT 外包到它自己的线程中,以便在新线程死亡时清除 ThreadLocalMap - 这释放了内存。见这里:https ://www.ahoi-it.de/ahoi/news/java-xslt-memory-leak/1446

于 2013-11-13T10:31:47.270 回答
0

我会检查你没有内存泄漏。文件的数量无关紧要,因为您一次只处理一个,只要您可以处理最大的文件,您就应该能够处理所有文件。

我建议您jstat -gc {pid} 10s在程序运行时运行以查找内存泄漏。您应该寻找的是 Full 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 回答