2013-09-22 49 views
2

我是Java的初级用户,面临内存泄漏问题。我一直认为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; 
} 
+1

你在技术上没有内存泄漏。 “吃所有的记忆”是什么意思?多少内存?你怎么知道这个线程是负责任的?毕竟,每次调用getList()时都会创建数千万个对象。 – chrylis

+0

这对我来说并不陌生。你不能有足够大的内存来保存一次迭代。 –

+0

以及它没有必要GC在下一轮释放内存。但是它的真实它应该在GC运行时释放 –

回答

3

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

a += "aaaa"; 

不是因为List没有被释放。

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

+0

我的不好:) ..... – alfasin

+1

没关系。你让我检查我的数学。哈哈。 :-D –

+0

'list'可能有40,000,000个字符。每次调用getList()都会生成一个100,000个元素的列表,每个元素包含400个字符。 – bsd

3

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

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

+0

对于GC,如果此程序执行一段时间,则表示执行得很好。# –

+0

+1包括字符串连接的中间结果。 –

+0

@亨利谢谢你的回答。以上是我遇到的问题的简单示例。也许这是我的错,不澄清这一点。 – Ellen

1

常见的误解是GC在不需要时立即释放内存。运行GC的成本很高,所以它会尽可能延迟(除非你使用Azul的Zing,在这种情况下它总是并发的)

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

但我认为它应该在每一轮释放内存,但它没有。

GC没有办法知道这是一个很好的运行时间。如果您想确认这将是一个很好的时间,你可以做一个

System.gc(); 
运行之间

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

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

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

如果您想查看内存泄漏,请将所有ArrayList保存在主ArrayList中。这应该导致OutOfMemoryError,并且你有泄漏。