Статьи

JAXB, SAX, DOM Performance

В этом посте рассматривается эффективность демонтажа XML-документа для объектов Java с использованием различных подходов. Документ XML очень прост. Он содержит коллекцию сущностей Person.

01
02
03
04
05
06
07
08
09
10
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persons>
    <person>
        <id>person0</id>
        <name>name0</name>
    </person>
    <person>
         <id>person1</id>
         <name>name1</name>
    </person>
...

Существует соответствующий Java-объект Person для объекта Person в XML
..

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "id",
    "name"
})
public class Person {
    private String id;
    private String name;
  
    public String getId() {
        return id;
    }
  
    public void setId(String id) {
        this.id = id;
    }
  
    public String getName() {
        return name;
    }
  
    public void setName(String value) {
        this.name = value;
    }
}

и объект PersonList для представления коллекции Persons.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "persons")
public class PersonList {
    @XmlElement(name="person")
    private List<person> personList = new ArrayList<person>();
  
    public List<person> getPersons() {
        return personList;
    }
  
    public void setPersons(List<person> persons) {
        this.personList = persons;
    }
}

Были исследованы следующие подходы:

  • Различные ароматы JAXB
  • SAX
  • DOM
Во всех случаях целью было получить сущности в документе XML для соответствующих объектов Java. Аннотации JAXB для POJOS Person и PersonList используются в тестах JAXB. Те же классы могут использоваться в тестах SAX и DOM (аннотации будут просто игнорироваться). Изначально ссылка

Были использованы реализации для JAXB, SAX и DOM. Затем был использован синтаксический анализ Woodstox STAX. Это можно было бы назвать в некоторых тестах JAXB.

Тесты проводились на моем ноутбуке Dell, двухъядерном процессоре Pentium с частотой 2,1 ГГц и Windows 7.

Тест 1 — Использование JAXB для демаршаллизации файла Java.

1
2
3
4
5
6
@Test
public void testUnMarshallUsingJAXB() throws Exception {
    JAXBContext jc = JAXBContext.newInstance(PersonList.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    PersonList obj = (PersonList)unmarshaller.unmarshal(new File(filename));
}

Тест 1 показывает, насколько проста модель прогамминга для JAXB. Очень легко перейти от файла XML к объектам Java. Нет необходимости связываться с мельчайшими деталями сортировки и разбора.

Тест 2 — Использование JAXB для демаршалла Streamsource


Тест 2 аналогичен Тесту 1, за исключением того, что на этот раз объект Streamsource оборачивается вокруг объекта File. Объект Streamsource дает подсказку реализации JAXB для потоковой передачи файла.

1
2
3
4
5
6
7
@Test
public void testUnMarshallUsingJAXBStreamSource() throws Exception {
    JAXBContext jc = JAXBContext.newInstance(PersonList.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    StreamSource source = new StreamSource(new File(filename));
    PersonList obj = (PersonList)unmarshaller.unmarshal(source);
}

Тест 3 — Использование JAXB для отмены вызова StAX XMLStreamReader

Снова аналогично Тесту 1, за исключением того, что на этот раз экземпляр XMLStreamReader оборачивает экземпляр FileReader, который не вызывается JAXB.

1
2
3
4
5
6
7
8
9
@Test
public void testUnMarshallingWithStAX() throws Exception {
    FileReader fr = new FileReader(filename);
    JAXBContext jc = JAXBContext.newInstance(PersonList.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    XMLInputFactory xmlif = XMLInputFactory.newInstance();
    XMLStreamReader xmler = xmlif.createXMLStreamReader(fr);
    PersonList obj = (PersonList)unmarshaller.unmarshal(xmler);
}

Тест 4 — Просто используйте DOM

Этот тест не использует JAXB и вместо этого просто использует подход JAXP DOM. Это означает, что сразу больше кода требуется, чем любой подход JAXB.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testParsingWithDom() throws Exception {
    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    Document doc = builder.parse(filename);
    List personsAsList = new ArrayList();
    NodeList persons = doc.getElementsByTagName("persons");
    for (int i = 0; i <persons.getLength(); i++) {
        Element person = (Element)persons.item(i);
        NodeList children = (NodeList)person.getChildNodes();
        Person newperson = new Person();
        for (int j = 0; j < children.getLength(); j++){
            Node child = children.item(i);
            if (child.getNodeName().equalsIgnoreCase("id")) {
                newperson.setId(child.getNodeValue());
            } else if (child.getNodeName().equalsIgnoreCase("name")) {
                newperson.setName(child.getNodeValue());
            }
        }
        personsAsList.add(newperson);
    }
}

Тест 5 — просто используйте SAX Тест 5 не использует JAXB и использует SAX для анализа XML-документа. Подход SAX включает в себя больше кода и больше сложности, чем любой подход JAXB. Разработчик должен принять участие в разборе документа.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Test
public void testParsingWithSAX() throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser saxParser = factory.newSAXParser();
    final List<person> persons = new ArrayList<person>();
    DefaultHandler handler = new DefaultHandler() {
        boolean bpersonId = false;
        boolean bpersonName = false;
        public void startElement(String uri, String localName,String qName,    Attributes attributes) throws SAXException {
     if (qName.equalsIgnoreCase("id")) {
                bpersonId = true;
                Person person = new Person();
                persons.add(person);
            } else if (qName.equalsIgnoreCase("name")) {
                bpersonName = true;
            }
        }
        public void endElement(String uri, String localName, String qName) throws SAXException {
        }
        public void characters(char ch[], int start, int length) throws SAXException {
     if (bpersonId) {
                String personID = new String(ch, start, length);
                bpersonId = false;
                Person person = persons.get(persons.size() - 1);
                person.setId(personID);
            } else if (bpersonName) {
                String name = new String(ch, start, length);
                bpersonName = false;
                Person person = persons.get(persons.size() - 1);
                person.setName(name);
            }
        }
    };
    saxParser.parse(filename, handler);
}

Тесты были выполнены 5 раз для 3 файлов, которые содержат коллекцию сущностей Person. Первый первый файл содержал 100 объектов лиц и был размером 5 КБ. Второй содержал 10 000 объектов и был размером 500 КБ, а третий содержал 250 000 объектов лица и был размером 15 Мег. Ни в одном из случаев не использовались XSD и не проводились проверки. Результаты приведены в таблицах результатов, в которых времена для разных прогонов разделены запятыми.

РЕЗУЛЬТАТЫ ТЕСТА

Сначала тесты выполнялись с использованием 32-битной JDK 1.6.26, и использовалась эталонная реализация для SAX, DOM и JAXB, поставляемая с JDK.

Unmarshall Тип 100 человек время (мс) 10K человек время (мс) 250K человек время (мс)
JAXB (по умолчанию) 48,13, 5,4,4 78, 52, 47,50,50 1522, 1457, 1353, 1308, 131
JAXB (StreamSource) 11, 6, 3,3,2 44, 44, 48,45,43 1191, 1364, 1144, 1142, 1136
JAXB (StAX) 18,2,1,1,1 111, 136, 89,91,92 2693, 3058, 2495, 2472, 2481
DOM 16,2,2,2,2 89,50, 55,53,50 1992, 2198, 1845, 1776, 1773
SAX 4, 2, 1,1,1 29, 34, 23,26,26 704, 669, 605, 589 591



JDK 1.6.26 Тестовые комментарии

  1. Первый раз, когда происходит беспорядочный вызов, обычно самый длинный.
  2. Использование памяти для JAXB и SAX аналогично. Это около 2 мегабайт для файла с 10 000 человек и 36 — 38 мегабайт для 250 000 человек. Использование памяти DOM намного выше. Для файла на 10000 человек это 6 Мег, для файла на 250 000 человек это больше, чем 130 Мег.
  3. Время исполнения для чистого SAX лучше. В частности, для очень больших файлов.

Те же самые тесты были проведены снова, используя тот же JDK (1.6.26), но на этот раз была использована реализация синтаксического анализа StAX в Woodstox.

Unmarshall Тип 100 человек время (мс) 10K человек время (мс) 250K человек время (мс)
JAXB (по умолчанию) 168,3,5,8,3 294, 43, 46, 43, 42 2055, 1354, 1328, 1319, 1319
JAXB (StreamSource) 11,3,3,3,4 43,42,47,44,42 1147, 1149, 1176, 1173, 1159
JAXB (StAX) 30,0,1,1,0 67,37,40,37,37 1301, 1236, 1223, 1336, 1297
DOM 103,1,1,1,2 136,52,49,49,50 1882, 1883, 1821, 1835, 1822
SAX 4, 2, 2,1,1 31,25,25,38,25 613, 609, 607, 595, 613



JDK 1.6.26 + комментарии к тесту Woodstox

  1. Опять же, первый раз, когда происходит демаршаллинг, обычно пропорционально дольше.
  2. Опять же, использование памяти для SAX и JAXB очень похоже. Оба намного лучше

    чем DOM. Результаты очень похожи на тест 1.

  3. Время захода на посадку JAXB (StAX) значительно улучшилось. Это связано с

    Вудстокс реализация StAX парсинга используется.

  4. Время исполнения для чистого SAX по-прежнему самое лучшее. в частности

    для больших файлов.

Те же самые тесты были проведены снова, но на этот раз я использовал JDK 1.7.02 и реализацию синтаксического анализа StAX в Woodstox.

Unmarshall Тип 100 человек время (мс) 10000 человек время (мс) 250 000 человек время (мс)
JAXB (по умолчанию) 165,5, 3, 3,5 611,23, 24, 46, 28 578, 539, 511, 511, 519
JAXB (StreamSource) 13,4, 3, 4, 3 43,24, 21, 26, 22 678, 520, 509, 504, 627
JAXB (StAX) 21,1,0, 0, 0 300,69, 20, 16, 16 637, 487, 422, 435, 458
DOM 22,2,2,2,2 420,25, 24, 23, 24 1304, 807, 867, 747, 1189
SAX 7,2,2,1,1 169,15, 15, 19, 14 366, 364, 363, 360, 358



JDK 7 + комментарии к тесту Woodstox:

  1. Время выполнения JDK 7 в целом намного лучше. Есть некоторые аномалии — при первом анализе файла на 100 человек и файла на 10000 человек.
  2. Использование памяти немного выше. Для SAX и JAXB это 2 — 4 мегабайта для файла на 10000 человек и 45 — 49 мегабайт для файла на 250 000 человек. Для DOM это снова выше. 5 — 7,5 мегабайт для файла на 10000 человек и 136 — 143 мегабайт для файла на 250 000 человек



Примечание: WRT все тесты

  1. Для файла на 100 человек анализ памяти не проводился. Использование памяти было слишком маленьким, и поэтому в нем была бы бессмысленная информация.
  2. Первая инициализация контекста JAXB может занять до 0,5 секунды. Это не было включено в результаты теста, поскольку это заняло это время только в первый раз. После этого JVM очень быстро инициализирует контекст (не более 5 мс). Если вы заметили такое поведение в используемой вами реализации JAXB, попробуйте выполнить инициализацию при запуске.
  3. Эти тесты представляют собой очень простой XML-файл. В действительности было бы больше типов объектов и более сложный XML. Тем не менее, эти тесты должны по-прежнему служить руководством.

Выводы:

  1. Время работы чистого SAX немного лучше, чем JAXB, но только для очень больших файлов. Если вы не используете очень большие файлы, разница в производительности не стоит беспокоиться. Преимущества модели прогамминга JAXB выигрывают над сложностью модели программирования SAX. Не забывайте, JAXB также предоставляет случайные обвинения, как это делает DOM. SAX не обеспечивает этого.
  2. Времена производительности выглядят намного лучше с Woodstox, если используется JAXB / StAX.
  3. Время исполнения с 64-битным JDK 7 выглядит намного лучше. Использование памяти выглядит немного выше.

Ссылка: JAXB, SAX, DOM Performance от нашего партнера JCG Алекса Стейвли в техническом блоге Дублина .

Статьи по Теме :