XPath.evaluate 性能在多次调用时速度变慢(荒谬地)
我正在尝试使用javax.xml.xpath包在具有多个命名空间的文档上运行XPath表达式,并且我遇到了愚蠢的性能问题。
我的测试文档是从一个真实的生产示例中提取的。它是大约600k的xml。该文档是一个相当复杂的 Atom 源。
我意识到我用XPath做的事情可以在没有XPath的情况下完成。但是,在其他劣质平台上的相同实现表现得要好得多。现在,重建我的系统以不使用XPath超出了我在现有时间内可以做的事情的范围。
我的测试代码是这样的:
void testXPathPerformance()
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(loadTestDocument());
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
NamespaceContext names = loadTestNamespaces();
//there are 12 namespaces in names. In this example code, I'm using
//'samplens' instead of the actual namespaces that my application uses
//for simplicity. In my real code, the queries are different text, but
//precisely the same complexity.
xp.setNamespaceContext(names);
NodeList nodes = (NodeList) xp.evaluate("/atom:feed/atom:entry",
doc.getDocumentElement(), XPathConstants.NODESET);
for(int i=0;i<nodes.getLength();i++)
{
printTimestamp(1);
xp.evaluate("atom:id/text()", nodes.item(i));
printTimestamp(2);
xp.evaluate("samplens:fieldA/text()", nodes.item(i));
printTimestamp(3);
xp.evaluate("atom:author/atom:uri/text()", nodes.item(i));
printTimestamp(4);
xp.evaluate("samplens:fieldA/samplens:fieldB/&at;attrC", nodes.item(i));
printTimestamp(5);
//etc. My real example has 10 of these xp.evaluate lines
}
}
当我在Nexus One上运行时(不是在调试器中,而是在连接USB的情况下),第一次通过循环时,每个xp.evaluate需要10ms到20ms的时间。到循环的第15次,每个xp.evaluate需要200ms到300ms。到循环结束时(其中有 150 个项目),每个 xp.evaluate 大约需要 500 毫秒-600 毫秒。nodes
我尝试过使用xp.compile()。编译全部需要<5ms。我已经完成了xp.reset()(没有区别)。我为每个评估做了一个新的XPath对象(增加约4ms)。
在执行期间,内存使用量似乎不会失控。
我在 JUnit 测试用例中的单个线程上运行此内容,该测试用例不会创建活动或任何内容。
我真的很困惑。
有没有人知道还有什么可以尝试的?
谢谢!
更新
如果我向后运行for循环(),那么前几个节点取500ms-600ms,最后几个节点快速运行10ms-20ms。因此,这似乎与调用次数无关,而是上下文接近文档末尾的表达式比上下文靠近文档开头的表达式花费更长的时间。for(int i=nodes.getLength()-1;i>=0;i--)
有没有人对我能做些什么有任何想法?