Java 1.6内存泄漏:HashMap和ArrayList

时间:2011-12-02 20:06:43

标签: java collections memory-leaks garbage-collection

编辑: 没有内存泄漏,只是对Netbeans Profiler告诉我的内容有点误解。实时分析结果 - >分配的对象是指在程序的生命周期内分配的TOTAL,而不是当前在内存中的总数。为此,获取堆转储。很抱歉这个混乱,但也许其他人会发现这一点,它会清除它们。


我使用NetBeans 7.0.1分析器来解决应用程序中的内存增长问题,并且看到了两个主要问题。我已经成功创建了测试应用程序,并在分析器中看到了相同的结果,如下所示。我无法在其他地方找到对这些的引用。

案例1:循环访问HashMap的入口集导致对象java.util.HashMap& EntryIterator增长。除了找出一个不同容器的解决方案之外,这里有什么可做的吗?每次在while循环中循环遍历集合对于我们的应用程序是必要的。

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    HashMap<Integer, Integer> map = new HashMap<Integer, Integer> ();
    map.put(1, 2);map.put(3, 4);map.put(5, 6);map.put(7, 8);
    while(true){
        for (Entry<Integer, Integer> entry : map.entrySet()) {
        Integer i = entry.getValue();
        }

        //app specific code here

        Thread.sleep(50);
    }
}

案例2:在循环中创建空ArrayLists会导致java.lang.Object []的增长。我希望ArrayLists在while循环结束时符合GC的条件。我的假设错了吗?或者还有什么在这里发挥作用?

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    while(run){
        ArrayList<Integer> a1 = new ArrayList<Integer>();
        ArrayList<Integer> a2 = new ArrayList<Integer>();

        // app specific code here

        Thread.sleep(50);
    }
}

6 个答案:

答案 0 :(得分:2)

我认为这两个代码示例都没有泄漏内存。您必须确保区分“堆增长直到垃圾收集器运行”和“堆永远增长”。如果您删除Thread.sleep调用并永久运行任一应用程序,它不应该崩溃,并且随着垃圾收集器运行,JVM的堆使用率应该上升和下降。您可以尝试在每个循环期间运行“System.gc()”并查看您的探查器是否仍显示泄漏。

答案 1 :(得分:0)

只要没有其他代码引用GC,您的第二个示例中的ArrayLists就有资格使用GC。此外,您无法控制执行垃圾收集的方式和时间。你知道你在使用什么垃圾收集器吗?你用任何特定的vm标志运行程序吗?在调用System.gc以强制进行垃圾回收后,您是否遇到过奇怪的行为?您的应用特定代码是否引用了您的数组列表?

答案 2 :(得分:0)

在你的两个示例方法中,即使GC运行它也不能声明这些对象。

即使您的对象在循环外被初始化,然后在某些编译器上,字节码与在循环内创建的字节码相同,也没有太大区别。

此外,您不能保证GC是否会运行并且您的对象将被回收。

编辑:

SO上的类似帖子

答案 3 :(得分:0)

虽然我找不到任何令人不安的内容,但我只是尝试了两个代码段。我删除了sleep以加快测试速度。垃圾收集器每秒工作几次疯狂,基本上清理整个年轻一代(尝试使用-XX:+PrintGCDetails -XX:+PrintGCTimeStamps):

[GC [PSYoungGen: 104272K->0K(99712K)] 105235K->963K(131968K), 0.0008090 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]

代码运行几分钟,CPU利用率非常高,但内存使用率稳定。两个代码示例中肯定存在无内存泄漏

你可能观察到的是堆的增量增长(JVM中的年轻代基本上是一个堆栈,在彼此之上分配新对象而不用担心垃圾)。垃圾收集在堆栈耗尽时运行。

答案 4 :(得分:0)

你所说的很多内容取决于:

// app specific code here

你在这里做的事情可能会影响垃圾收集。对于您发布的代码,这将导致内存泄漏。例如,每次通过这个循环:

public static void main(String[] args) throws InterruptedException {
    boolean run = true;
    while(run){
        ArrayList<Integer> a1 = new ArrayList<Integer>();
        ArrayList<Integer> a2 = new ArrayList<Integer>();

        // app specific code here

        Thread.sleep(50);
    }
}

分配的对象可用于垃圾回收。

表示,内存可能会继续增长,直到达到其分配的限制为止,但此后对象将被垃圾收集。

在netbeans之外运行您的代码,并在其上运行jvisualvm。看看到底发生了什么。

答案 5 :(得分:0)

我运行了上面的代码,我可以确认这不是内存泄漏。因为当我运行GC时,所有的ArrayList对象都被回收。假设它注释了应用程序代码并没有累积问题

此致 拉莉莎