我是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;
}
答案 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并且您有泄漏。