Xpath内存泄漏? [英] Xpath memory leak?

查看:75
本文介绍了Xpath内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用标准Java库(1.6.0_27)评估XPath表达式时,似乎存在内存泄漏.

There appears to be a memory leak when using the standard Java library (1.6.0_27) for evaluating XPath expressions.

有关重现此问题的一些代码,请参见下文:

See below for some code to reproduct this problem:

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文件:

An example XML file is given below:

<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类的分配似乎也不断增加.

When I run this example using the NetBeans profiler it appears that the allocations for the com.sun.org.apache.xpath.internal.objects.XObject class keeps increasing, even after garbage collection.

我是否以不正确的方式使用XPath库?这是Java库中的错误吗?有潜在的解决方法吗?

Am I using the XPath library in an incorrect way? Is this a bug in the Java libraries? Are there are potential workarounds?

推荐答案

在这种情况下,没有内存泄漏".内存泄漏定义为应用程序无法回收内存的实例.在这种情况下,不会发生泄漏,因为所有XObject(和XObject[])实例都可以在某个时间点回收.

There is no "memory leak" in this case. Memory leak are defined as instances where an application cannot reclaim memory. In this case there is no leak, as all XObject (and XObject[]) instances can be reclaimed at some point in time.

从VisualVM获得的内存探查器快照会产生以下观察结果:

A memory profiler snapshot obtained from VisualVM yields the following observations:

  • 调用XPathExpression.evaluate方法时,将创建所有XObject(和XObject[])实例.
  • 当从GC根目录不再可访问
  • XObject实例时,将对其进行回收.在您的情况下,GC根是resulttestResult局部变量,它们在主线程堆栈中是本地的.
  • All XObject (and XObject[]) instances are created when the XPathExpression.evaluate method is invoked.
  • XObject instances are reclaimed when they are no longer reachable from a GC root. In your case, the GC roots are the result and testResult local variables which are local to the stack of the main thread.

基于上述情况,我想您的应用程序正在经历或很可能会经历内存耗尽(而不是内存泄漏).当您有大量来自XPath表达式求值的XObject/XObject[]实例,但由于

Based on the above, I suppose that your application is experiencing or likely to experience a memory exhaustion as opposed to a memory leak. This is true when you have a large number of XObject/XObject[] instances from an XPath expression evaluation, that haven't been reclaimed by the garbage collector because

  • 它们仍然可以从GC根目录访问,
  • 或者垃圾收集器还没有来回收它们.

第一个解决方案的唯一解决方案是在所需的时间内将对象保留在内存中.您似乎并没有在代码中违反它,但是您的代码肯定可以提高效率-您可以保留第一个XPath表达式的结果,而第二个表达式可以在更高效地执行时使用它. //Product/Test可用于检索Test节点,并获取父级Product节点的id值,如以下代码段所示(该代码仅计算一个XPath表达式,而不是两个):

The only solution to the first is to retain objects around in memory for the duration that they are required. You do not seem to be violating that in your code, but your code could certainly be made more efficient - you are retaining the result of the first XPath expression, to be used by the second, when certainly it could be performed more efficiently. //Product/Test can be used to retrieve the Test nodes, and also obtain the parent Product Nodes' id values are shown in the following snippet (which evaluates only one XPath expression instead of two):

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循环的每几次迭代中完成一次年轻的gen收集周期,因为该循环局部的XObject实例应在该块的局部变量后立即回收超出范围.

As far as the second observation is concerned, you ought to obtain GC logs (using the verbose:gc JVM startup flag). You could then decide to resize the young generation, if you have too many shortlived objects being created, as there is the possible likelihood that reachable objects will be moved to the tenured generation resulting in the likelihood that a major collection will be required to reclaim objects that are actually shortlived by nature. In an ideal scenario (considering your posted code), a young gen collection cycle should be done every few iterations of the for loop, as the XObject instances that are local to the loop, should be reclaimed as soon as the block's local variables go out of scope.

这篇关于Xpath内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆