为什么Java不释放内存

时间:2013-09-22 07:22:04

标签: java multithreading memory

我是Java的大三学生,面临内存泄漏问题。我一直以为java不会有内存问题,但我有一个。以下是我的测试代码。

我在getList()方法中创建一个大型ArrayList,并继续在主线程中调用此方法。我想清单:

ArrayList<String> list = t.getList();
循环中的

是一个局部变量,应该在下一轮中释放,因为会创建一个新对象。但是jvm并没有这样做。这个线程继续吃掉所有的记忆。有人能告诉我原因吗?谢谢!

测试代码:

package test;

import java.util.ArrayList;

public class test {


public static void main(String[] args){

    test t = new test();
    for(int k = 0; k < 10000; k ++){
        ArrayList<String> list = t.getList();

        System.out.println(k);
    }

}

public ArrayList<String> getList(){
    ArrayList<String> list = new ArrayList<String>();

    for(int i = 0; i < 100000; i ++){
        String a = "";
        for(int j = 0; j < 100; j++){
            a += "aaaa";
        }
        list.add(a);
    }

    return list;
}
}

修改问题: 在修改过的问题中,线程还会继续吃掉内存。但我认为它应该在每一轮中释放记忆,但事实并非如此。所以它占用了越来越多的记忆。

public static void main(String[] args){

    test t = new test();
    for(int k = 0; k < 10000; k ++){
        String str1 = "string1";
        String str2 = "string2";
        double value = t.calculate(str1, str2);

        System.out.println(k + " " + value);
    }

}

public double calculate(String str1, String str2){
    double value = 0.0;

    ArrayList<String> list1 = getList(str1);
    ArrayList<String> list2 = getList(str2);

    value = cal(list1, list2); //will get the value based on lists

    return value;

}


public ArrayList<String> getList(String str1){
    ArrayList<String> list = new ArrayList<String>();

    //will generate  a long list

    return list;
}

3 个答案:

答案 0 :(得分:3)

我猜这是因为迭代的字符串连接:

a += "aaaa";

不是因为List没有被释放。

最后,a中有40,000,000个字符。

答案 1 :(得分:3)

getList的一次调用将为2000000000个字符分配空间(这包括字符串连接的中间结果)。这是4GB,不算开销。所有这些都是循环完成10000次,总分配为40TB。

如果这个程序执行了一段时间,GC就做得很好。

答案 2 :(得分:1)

常见的误解是GC在不需要的情况下尽快释放内存。运行GC的成本很高,因此它会尽可能延迟(除非您使用Azul的Zing,在这种情况下它始终是并发的)

这意味着,当您创建越来越多的垃圾时,看到内存消耗增加是完全正常的,并且知道您是否有内存泄漏的唯一方法是查看完整GC之后的消耗。在运行完整GC之前,您可以确定某些可能已清理过的对象尚未清除。

  

但我认为它应该在每一轮中释放记忆,但事实并非如此。

GC无法知道这是一个运行的好时机。如果你想确认这是个好时机,你可以做一个

System.gc();
运行之间的

。调用它后的内存使用量应该非常稳定。之所以不经常使用这个调用的原因是通常它会使事情变得更糟,除非你知道,例如,那时你已经倾倒了应用程序使用的几乎所有内存。

  

面临内存泄漏问题。我一直以为java不会有内存问题,但我有一个。

您可以在Java程序中发生内存泄漏,但我没有看到任何证据表明您有。

如果要查看内存泄漏,请保存main中ArrayList中的所有ArrayList。这应该导致OutOfMemoryError并且您有泄漏。