Утечка памяти Xpath? - PullRequest
       3

Утечка памяти Xpath?

1 голос
/ 08 сентября 2011

При использовании стандартной библиотеки Java (1.6.0_27) для оценки выражений XPath возникает утечка памяти.

Ниже приведен код для воспроизведения этой проблемы:

public class XpathTest {

    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        docFactory.setNamespaceAware(true);
        DocumentBuilder builder = docFactory.newDocumentBuilder();
        Document doc = builder.parse("test.xml");

        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("//Product");

        Object result = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList nodes = (NodeList) result;
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            System.out.println(node.getAttributes().getNamedItem("id"));

            XPathExpression testExpr = xpath.compile("Test");
            Object testResult = testExpr.evaluate(node, XPathConstants.NODE);
            Node test = (Node) testResult;
            System.out.println(test.getTextContent());
        }
        System.out.println(nodes.getLength());
    }
}

Пример XML-файла приведен ниже:

<Products>
  <Product id='ID0'>
    <Test>0</Test>
  </Product>
  <Product id='ID1'>
    <Test>1</Test>
  </Product>
  <Product id='ID2'>
    <Test>2</Test>
  </Product>
  <Product id='ID3'>
    <Test>3</Test>
  </Product>
  ...
</Products>

Когда я запускаю этот пример с использованием профилировщика NetBeans, оказывается, что выделения для класса com.sun.org.apache.xpath.internal.objects.XObjectпродолжает увеличиваться, даже после сборки мусора.

Я неправильно использую библиотеку XPath?Это ошибка в библиотеках Java?Существуют ли потенциальные обходные пути?

Ответы [ 3 ]

2 голосов
/ 08 сентября 2011

В этом случае нет «утечки памяти».Утечка памяти определяется как случаи, когда приложение не может восстановить память.В этом случае утечки нет, поскольку все экземпляры XObjectXObject[]) могут быть восстановлены в определенный момент времени.

Снимок профилировщика памяти, полученный из VisualVM, дает следующие наблюдения:

  • Все экземпляры XObjectXObject[]) создаются при вызове метода XPathExpression.evaluate.
  • XObject экземпляры восстанавливаются, когда они более недоступны из корня GC,В вашем случае корнями GC являются локальные переменные result и testResult, которые являются локальными для стека основного потока.

Исходя из вышеизложенного, я полагаю, что ваше приложение испытываетили может возникнуть истощение памяти, а не утечка памяти.Это верно, когда у вас есть большое количество XObject / XObject[] экземпляров из оценки выражения XPath, которые не были восстановлены сборщиком мусора, потому что

  • они все еще доступны изкорень GC,
  • или сборщик мусора еще не пришел, чтобы вернуть их.

Единственное решение первого - это сохранить объекты в памяти на время, котороеони необходимы.Похоже, вы не нарушаете это в своем коде, но ваш код, безусловно, можно сделать более эффективным - вы сохраняете результат первого выражения XPath, которое будет использоваться вторым, когда, безусловно, его можно будет выполнять более эффективно.//Product/Test может использоваться для извлечения Test узлов, а также для получения родительских значений Product Идентификаторы узлов показаны в следующем фрагменте (который оценивает только одно выражение XPath вместо двух):

expr = xpath.compile("//Product/Test");
nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++)
{
    Node node = nodes.item(i);
    System.out.println(node.getParentNode().getAttributes().getNamedItem("id"));
    System.out.println(node.getTextContent());
}
System.out.println(nodes.getLength());

Что касается второго наблюдения, вы должны получить журналы GC (используя флаг запуска verbose:gc JVM).Затем вы можете принять решение изменить размеры молодого поколения, если у вас создано слишком много недолговечных объектов, поскольку существует вероятность того, что достижимые объекты будут перемещены в постоянное поколение, что приведет к вероятности того, что для восстановления объектов потребуется большая коллекция.которые на самом деле недолговечны по своей природе.В идеальном сценарии (с учетом вашего опубликованного кода) цикл сбора данных молодого поколения должен выполняться каждые несколько итераций цикла for, поскольку экземпляры XObject, которые являются локальными для цикла, должны возвращаться, как только локальные переменные блокавыйти за рамки.

2 голосов
/ 08 сентября 2011

Не знаю, может ли это быть причиной утечки памяти, но:

XPathExpression testExpr = xpath.compile("Test");

Не делайте этого в цикле for.Скомпилируйте его один раз за цикл for и используйте его снова.Может быть, объект XPath кэширует все выражения, которые вы компилируете для повторного использования?

0 голосов
/ 08 сентября 2011

Вы говорите: «объекты, выделенные для типа com.sun.org.apache.xpath.internal.objects.XObject, постоянно увеличиваются при анализе файла».

Я думаю, вы найдете это по замыслу. Я не знаю внутренностей инструментов Apache, но вы должны ожидать, что обычная (не потоковая) реализация DOM и XPath будет использовать объем памяти, пропорциональный размеру исходного документа.

Таким образом, я ожидаю, что требования к памяти увеличатся при разборе исходного документа. Я не ожидал бы, что он увеличится, поскольку все больше выражений XPath выполняются для этого документа (после того, как были исключены эффекты, что некоторая сборка дерева выполняется лениво, при первом обращении к каждому узлу.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...