我正在根据内存消耗优化现有的 XML 到 XML 转换过程。我们正在将大型的多 GB XML 文件转换为更小的内部 XML 结构 - 结果大小小于 10%。该转换在 4 个不同的 XSLT 阶段中实现 - 基本上我们这样做:
sourcefile.xml -> xslt1 -> xslt2 -> xslt3 -> xslt4 -> targetfile.xml
这是使用 SAX-api 和 saxon 作为不可流式链式转换来实现的。 到目前为止,所有 4 个转换均已调整为可突发流式传输。作为其中的一部分,我们还更改了调用 Java 实现,以使用带有 Xslt30Transformer 的 saxon s9api(测试已使用 Saxon 10.6 完成)。
我们看到以下模式,测试源文件大小为 500 MB。
trafo.asDocumentDestination(nextTrafo)
链接可流式 trafos,我们需要 4GB 内存来运行它,否则它会因“超出 GC 开销限制”而停止。我们可以仅通过链接 4 个 trafo 中的 2 个来重现这一点:
我们问自己这是否是预期的和正常的,因为使用链式流媒体可能需要在 trafos 之间缓冲数据?或者我们的实施有问题...
因此,我们显然可以在 trafos 之间保存到磁盘,并有 4 个单独的步骤,每个步骤消耗 200MB - 但这对于在 trafos 之间流式传输到磁盘真的是最佳选择吗?
这种行为是预期的还是我们的实现有问题?
我们的(简化的)代码如下所示:
// trafo1234 are Xslt30Transformer we got using xsltCompiler.compile().load30()
Serializer finalDest = trafo4.newSerializer(Files.newOutputStream(outFile));
StreamSource input = Files.newInputStream(inFile);
trafo1.applyTemplates(input,
trafo2.asDocumentDestination(
trafo3.asDocumentDestination(
trafo4.asDocumentDestination(finalDest))));
PS:有没有一种简单的方法来查看/测量转换的内存需求?到目前为止,我发现的唯一方法是使用 -Xmx 直到出现 OOM-Exception
看起来您尝试使用
Xslt30Transformer.asDocumentDestination()
实现流式管道似乎不起作用,并且中间树(或至少其中之一)正在内存中构建。从提供的信息来看,这并不明显。 Saxon 采用的关键测试是 initialMode().isDeclaredStreamable()
;如果返回 false 那么它将构建树。
我建议创建一个重现来演示问题并将其发送给我们,最好作为 saxonica.plan.io 上的支持请求,这样它就不会丢失。
设置处理器/配置属性
Feature.TIMING
应会导致消息指示正在构建树(如果是这种情况)。