注意:如果你也遇到了这个问题,请在Apache:上向上投票。
https://issues.apache.org/jira/browse/XALANJ-2540
我得出了一个令人惊讶的结论:
Element e = (Element) document.getElementsByTagName("SomeElementName").item(0);
String result = ((Element) e).getTextContent();看起来比这个快了100倍:
// Accounts for 30%, can be cached
XPathFactory factory = XPathFactory.newInstance();
// Negligible
XPath xpath = factory.newXPath();
// Negligible
XPathExpression expression = xpath.compile("//SomeElementName");
// Accounts for 70%
String result = (String) expression.evaluate(document, XPathConstants.STRING);我使用的是JVM的默认JAXP实现:
org.apache.xpath.jaxp.XPathFactoryImpl
org.apache.xpath.jaxp.XPathImpl我真的很困惑,因为很容易看出JAXP如何优化上面的XPath查询来实际执行一个简单的getElementsByTagName()。但它似乎并没有做到这一点。这个问题仅限于5-6个频繁使用的XPath调用,这些调用被API抽象并隐藏起来。这些查询只涉及针对始终可用的DOM文档的简单路径(例如,/a/b/c、无变量、条件)。因此,如果可以进行优化,这将是相当容易实现的。
我的问题是:XPath的缓慢是一个公认的事实,还是我忽略了什么?有没有更好(更快)的实现?或者,对于简单的查询,我应该完全避免使用XPath吗?
发布于 2011-06-14 17:45:03
我已经调试和分析了我的测试用例和Xalan/JAXP。我设法找出了
org.apache.xml.dtm.ObjectFactory.lookUpFactoryClassName()可以看出,10k个测试XPath评估中的每一个都会导致类加载器尝试在某种默认配置中查找DTMManager实例。此配置不会加载到内存中,但每次都会被访问。此外,这种访问似乎受到ObjectFactory.class本身的锁的保护。当访问失败时(默认情况下),将从xalan.jar文件的
META-INF/service/org.apache.xml.dtm.DTMManager配置文件。每次都是!

幸运的是,可以通过如下所示指定JVM参数来覆盖此行为:
-Dorg.apache.xml.dtm.DTMManager=
org.apache.xml.dtm.ref.DTMManagerDefault或
-Dcom.sun.org.apache.xml.internal.dtm.DTMManager=
com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault上面的方法是有效的,因为如果工厂类名是默认的,这将允许在lookUpFactoryClassName()中绕过昂贵的工作:
// Code from com.sun.org.apache.xml.internal.dtm.ObjectFactory
static String lookUpFactoryClassName(String factoryId,
String propertiesFilename,
String fallbackClassName) {
SecuritySupport ss = SecuritySupport.getInstance();
try {
String systemProp = ss.getSystemProperty(factoryId);
if (systemProp != null) {
// Return early from the method
return systemProp;
}
} catch (SecurityException se) {
}
// [...] "Heavy" operations later下面是对一个90kXML文件(用System.nanoTime()测量)进行10k次连续XPath评估的//SomeNodeName性能改进概览
measured library : Xalan 2.7.0 | Xalan 2.7.1 | Saxon-HE 9.3 | jaxen 1.1.3
--------------------------------------------------------------------------------
without optimisation : 10400ms | 4717ms | | 25500ms
reusing XPathFactory : 5995ms | 2829ms | |
reusing XPath : 5900ms | 2890ms | |
reusing XPathExpression : 5800ms | 2915ms | 16000ms | 25000ms
adding the JVM param : 1163ms | 761ms | n/a |注意,基准测试是一个非常原始的基准测试。您自己的基准测试很可能会显示saxon优于xalan
我已经将此作为bug提交给Apache的Xalan人员:
发布于 2011-12-23 15:32:06
不是一个解决方案,而是指向主要问题的指针:相对于任意节点计算xpath的过程中,最慢的部分是DTM管理器查找节点句柄所用的时间:
http://javasourcecode.org/html/open-source/jdk/jdk-6u23/com/sun/org/apache/xml/internal/dtm/ref/dom2dtm/DOM2DTM.html#getHandleOfNode%28org.w3c.dom.Node%29
如果有问题的节点在文档的末尾,那么对于每个查询,它可能会遍历整个树来查找有问题的节点。
这解释了为什么孤立目标节点的黑客攻击有效。应该有一种方法来缓存这些查找,但在这一点上,我看不到如何缓存。
发布于 2013-07-29 16:14:49
为了回答你的问题,vtd-xml比Jaxen或Xalan快得多(我会说平均快10倍,据报道是60倍……
https://stackoverflow.com/questions/6340802
复制相似问题