Некоторое время назад в Apache Xalan была некоторая неловкая ошибка, и это ошибка XALANJ-2540 . Результатом этой ошибки является то, что внутренний файл конфигурации SPI загружается Xalan тысячи раз за оценку выражения XPath, что можно легко измерить следующим образом:
это:
1
2
3
4
|
Element e = (Element) document.getElementsByTagName( "SomeElementName" ) .item( 0 ); String result = ((Element) e).getTextContent(); |
Кажется, невероятно в 100 раз быстрее, чем это:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
// 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); |
Можно видеть, что каждый из тестов XPath с тестом 10k приводил к тому, что загрузчик классов пытался DTMManager
экземпляр DTMManager
в какой-то конфигурации по умолчанию. Эта конфигурация не загружается в память, а доступна каждый раз. Кроме того, этот доступ, кажется, защищен блокировкой самого ObjectFactory.class
. При сбое доступа (по умолчанию) конфигурация загружается из файла конфигурации файла xalan.jar
:
1
|
META-INF/service/org.apache.xml.dtm.DTMManager |
Каждый раз! :
К счастью, это поведение можно изменить, указав параметр JVM следующим образом:
1
2
|
-Dorg.apache.xml.dtm.DTMManager= org.apache.xml.dtm.ref.DTMManagerDefault |
или же
1
2
|
-Dcom.sun.org.apache.xml.internal.dtm.DTMManager= com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault |
Вышеприведенное работает, так как это позволит обойти дорогостоящую работу в lookUpFactoryClassName (), если имя класса фабрики все равно является значением по умолчанию:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
// Code from c.s.o.a.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 |
Ресурсы
Приведенный выше текст является выдержкой из вопроса и ответа о переполнении стека, который я предоставил общественности некоторое время назад. Я снова публикую это здесь, в моем блоге, так что осведомленность сообщества об этой довольно серьезной ошибке может быть повышена. Не стесняйтесь высказаться по этому билету здесь, так как это влияет на каждый JDK Sun / Oracle на этой планете: https://issues.apache.org/jira/browse/XALANJ-2540
Внесение исправления в Apache было бы еще лучше, конечно …