我已经测量了使用 Jaxb2 将 XML 解组为对象的时间成本,该对象使用带有较长(48 个字符)标签名称的大型(1.7mb)XML 有效负载。我通过在采样模式下运行的 JProfiler 观察到字符串实习工作是所花费时间的重要组成部分。
我做了一些研究,发现 Jaxb 可以在不实习字符串的模式下运行。我的理论是,在某些情况下,在解组期间不暂留字符串可能会以使用更多堆内存为代价来提高性能,因为在暂留过程中不必对每个标签名称字符串进行哈希处理。
我用来抑制 Jaxb 的实习行为的方法是在我的 Fastinfoset“StAXDocumentParser”(实现 XMLStreamReader)上设置“org.codehaus.stax2.internNames”和“org.codehaus.stax2.internNsUris”属性。我不是 100% 清楚为什么必须将这些设置为“true”以防止 Jaxb 对字符串进行实习,但这就是它的工作原理。
这些 JUnit 驱动的测试是我过去得出的结论,即禁用 Jaxb 的字符串实习行为会产生很大的性能差异:
https://github.com/gjd6640/fastinfoset-performance-evaluation
所以我的问题是多方面的:
1)我是否误解了一些重要的事情,不应该首先尝试禁用 Jaxb 的字符串实习行为?
2)有没有更好的方法来指导 Jaxb 不实习字符串?“StAXManager”类不允许您设置这些面向 Woodstox 的属性。对于这个测试,我最终扩展了 StAXManager,如下所示来解决这个问题。这是我不希望在生产中使用的 hack。我怀疑这里的想法是,当 Jaxb 从 Woodstox 流中解组时,它会查看 Woodstox 是否已经在进行实习,并且当“是”时,Jaxb 通过禁用该过程的步骤来做出反应。我通过在 Jaxb 库中捎带该逻辑来作弊,所以想要一个更好的方法来解决这个问题。
package com.sun.xml.fastinfoset.stax;
public class JaxbStringInternSuppressionStaxManager extends StAXManager {
public JaxbStringInternSuppressionStaxManager() {
// Add to the allowable list of feature names so that the user may set these "StAXInputFactory" properties
super.features.put("org.codehaus.stax2.internNames", null);
super.features.put("org.codehaus.stax2.internNsUris", null);
}
}
更新:
像往常一样,“一个很好的问题得到了一半的回答”。我刚刚在起草这个问题时注意到“com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector”检查类“com.sun.xml.internal .fastinfoset.stax.StAXDocumentParser ”是否是可从您正在使用的 XMLStreamReader 分配,如果是这样,则不启用字符串实习。在我的情况下,我的流对象是“com.sun.xml.fastinfoset.stax.StAXDocumentParser”,所以实习不会被禁用。现在的问题是“为什么它只是为了 Fastinfoset 库的内部风格才这样做?” 或许我会仔细阅读这篇文章找到答案。
此外,如果有更好的论坛来解决此类问题,例如活跃的开发人员用户组,请分享该信息,我会看到将它们链接到这篇文章,以便合适的人看到这个问题。