超出了由阵列创建引起的垃圾收集器开销限制

时间:2017-12-06 15:51:16

标签: java arrays garbage-collection heap-memory

您好,

我的程序花了很多时间在堆内存中创建对象,所以在某个时间我得到这个错误:

  

线程“main”中的异常java.lang.OutOfMemoryError:超出GC开销限制

我不能把我的完整应用程序放在这个讨论中所以我创建了一个原型来解释我的程序在做什么。

我的程序中涉及创建对象的部分看起来像是Follows:

**The Calling Program :**

public class Example {


public static void main(String[] args) {
        ArrayList list = new ArrayList();
        for (int i = 0; i < 5000; i++) {
            for (int j = 0; j < 5000; j++) {
                if (i==j)
                    continue;
                int weight = new Random().nextInt();
                Edge edge = new Edge(new Vertex(i+""), new Vertex(j+""),weight);
                list.add(edge);
            }
        }
  }

}

班级顶点:

public class Vertex {
    private String sequence ;

    public Vertex() {
    }

    public Vertex(String seq) {
        this.sequence = seq;
    }

}

班级边缘:

public class Edge {

    private Vertex source;
    private Vertex destination;
    private int weight;

    public Edge() {

    }

    public Edge(Vertex source, Vertex destination, int weight) {
        int[][] array = new int[500][500];
        //here i need the array to do some calculation
        anotherClass.someCalculation(array,source,destination);
        this.source = source;
        this.destination = destination;
        this.weight = weight;

    }
}

所以你可以看到:

我有5000个顶点,我需要创建5000 * 5000边,每个边都有一个长度为500 * 500的数组。

由于这个原因,在堆内存中分配的内存在特定时间结束,我从许多方面了解到的问题是,没有保证垃圾收集器会释放内存。

那么这个问题的解决方案是什么?通常我在构建Edge之后不需要Edge的数组;只有在构造边缘时才需要数组。

另一个问题:如何最小化程序中的内存利用率?我试图将int数组转换为char数组,但它没有帮助。

非常感谢

3 个答案:

答案 0 :(得分:0)

您的程序实际上创建了2 * 5000 * 5000个顶点,即内部(j)循环的每次迭代的一对顶点。我认为你需要首先创建5k顶点,并在创建边时保持对数组的引用。

我假设“array”变量仅为计算所需 。如果是,则使用局部变量而不是实例变量。这样你就不会保留该阵列的5k个实例 - 只需一个完成计算 - 减少内存使用量。

重新定义Edge类:

public class Edge {

private Vertex source;
private Vertex destination;
private int weight;
//private int  [][] array;  // don't keep an instance copy of this array if
                            // if it is not needed beyond the calculation.

public Edge() {

}

public Edge(Vertex source, Vertex destination, int weight) {
    int[][] array = new int[500][500];  // array will gc eligible after 
                                        // constructor completes
    //here i need the array to do some calculation
    anotherClass.someCalculation(array,source,destination);
    this.source = source;
    this.destination = destination;
    this.weight = weight;

}

}

答案 1 :(得分:0)

您的代码问题是由于以下原因造成的。 每次创建Edge类的对象

Edge edge = new Edge(new Vertex(i), new Vertex(j),weight);

调用以下构造函数

public Edge(Vertex source, Vertex destination, int weight)

因此,对于Edge类的每个对象创建,将创建以下500 X 500整数数组

int[][] array = new int[500][500]; 

因为你创建了大约5000个{1000}类Edge类的对象而消耗大量内存。

因此,如果要存储边权重,请尝试为其创建全局整数数组。

答案 2 :(得分:0)

知道数组索引引用是4个字节很重要。因此定义为500,500的二维数组是1MB而没有存储任何数据。您还要创建5000 x 5000。只有没有其他数据的数组将超过25TB。

当GC将大部分时间花费在垃圾收集视图结果上时,会发生GC开销限制。这是可以预料到的,因为创建的所有数组都可以从主线程中访问。

您应该根据需要创建和扩展数组(想想ArrayList)或者只在需要时创建数组。

如果您绝对需要内存中的所有边缘,则需要增加堆或学习序列化结果并仅加载计算所需的内容。