XSLT 3.0 与 saxon 链接突发流 - 内存消耗注意事项

问题描述 投票:0回答:1

我正在根据内存消耗优化现有的 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。

  • 不可流式链接 SAX 进程的内存需求:-Xmx 2GB
  • 单个流传输 trafo 阶段的内存需求:小于 200MB,与 -Xmx200M 一起运行良好 - 这将是完美的。
  • 如果我们使用多个
    trafo.asDocumentDestination(nextTrafo)
    链接可流式 trafos,我们需要 4GB 内存来运行它,否则它会因“超出 GC 开销限制”而停止。

我们可以仅通过链接 4 个 trafo 中的 2 个来重现这一点:

  • 两者均使用 Xmx200M 单独执行。
  • 链式执行需要-Xmx4G才能运行。

我们问自己这是否是预期的和正常的,因为使用链式流媒体可能需要在 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

java xslt streaming saxon xslt-3.0
1个回答
0
投票

看起来您尝试使用

Xslt30Transformer.asDocumentDestination()
实现流式管道似乎不起作用,并且中间树(或至少其中之一)正在内存中构建。从提供的信息来看,这并不明显。 Saxon 采用的关键测试是
initialMode().isDeclaredStreamable()
;如果返回 false 那么它将构建树。

我建议创建一个重现来演示问题并将其发送给我们,最好作为 saxonica.plan.io 上的支持请求,这样它就不会丢失。

设置处理器/配置属性

Feature.TIMING
应会导致消息指示正在构建树(如果是这种情况)。

© www.soinside.com 2019 - 2024. All rights reserved.