运行Java代码时内存不足

时间:2011-02-15 19:02:18

标签: java heap

我有一个数据集保存为文本文件,基本上包含逐行存储的向量。我的向量是10k的维度,我有250个这样的向量。每个向量条目都是双精度数。这是一个例子:

Vector 1 - > 0.0 0.0 0.0 0.439367 0.0 ..... 10k这样的条目

Vector 2 - > 0.0 0.0 0.0 0.439367 0.0 0.0 0.0 0.0 ...... 10k这样的条目

...

...

Vector 250 - > 0.0 1.203973 0.0 0.0 0.0 ...... 10k这样的条目

现在,如果我进行数学运算,这应该占用10k X 16bytes X 250空间(假设每个向量条目是一个占用16字节空间的双倍),这是大约40MB的空间。但是我发现文件大小仅显示为9.8MB。我在某个地方出错了吗?

问题是我在我的Java代码中使用这些数据。我的算法的空间复杂度是O(向量X no条目中没有条目)。即使我通过分配4GB的内存来运行我的代码,我仍然会耗尽堆空间。我错过了什么?

感谢。 安迪

5 个答案:

答案 0 :(得分:2)

在这么多人猜测大小之后,我做了3个简单的测试,并使用Eclipse Memory Analyzer来确定大小。 (Win7,1.6.0_21 Java HotSpot(TM)64位服务器VM)

  • double[][] =大小:19,2 MB类:328对象:2,7k
  • Double[][] structure =大小:76,5 MB类:332对象:2.5米
  • ArrayList<ArrayList<Double>> =大小:79,6 MB类:330对象:2.5米

256MB(java -Xmx256m Huge)足以运行测试。

所以我猜问题不是大小,可能是两件事:

  • 算法中存在错误
  • jvm不能运行4GB

如果有人对代码感兴趣:

import java.util.ArrayList;
import java.util.List;

public class Huge {

    private static final int NUMBER_OF_VECTORS = 250;
    private static final int VECTOR_SIZE = 10000;

    //Size: 19,2 MB Classes: 328 Objects: 2,7k 
    public static void doulbeArray() {

        double[][] structure = new double[NUMBER_OF_VECTORS][];

        for(int i = 0; i < NUMBER_OF_VECTORS; i++) {
            structure[i] = new double[VECTOR_SIZE];
        }
    }

    //Size: 76,5 MB Classes: 332 Objects: 2,5m
    public static void doubleWrapperArray() {

        Double[][] structure = new Double[NUMBER_OF_VECTORS][];

        for(int i = 0; i < NUMBER_OF_VECTORS; i++) {
            structure[i] = new Double[VECTOR_SIZE];
            for (int k = 0; k < VECTOR_SIZE; k++) {
                structure[i][k] = Double.valueOf(Math.random());
            }
        }
    }

    //Size: 79,6 MB Classes: 330 Objects: 2,5m 
    public static void list() {

        List<List<Double>> structure = new ArrayList<List<Double>>(); 

        for(int i = 0; i < NUMBER_OF_VECTORS; i++) {
            List<Double> vector = new ArrayList<Double>();            
            for (int k = 0; k < VECTOR_SIZE; k++) {
                vector.add(Double.valueOf(Math.random()));
            }
            structure.add(vector);
        }
    }
}

答案 1 :(得分:0)

在没有看到代码的情况下,我无法肯定地说,但是当你要么a)从文件中读取数据或b)算法中的某个地方时,听起来你过度分配。我建议您使用visualVM等工具来检查对象分配 - 它将能够告诉您如何分配以及您正在犯的错误。

答案 2 :(得分:0)

  

现在,如果我做数学,这应该采取   高达10k X 16bytes X 250空间(假设   每个向量条目都是双重的   最多16个字节),大约40MB   空间。但是我看到了那个文件   尺寸仅显示为9.8MB。我   在某个地方出错了?

你出错的地方是假设每个double在保存为文本时占用16个字节的空间。你似乎有很多0值,它们只占字符串形式的4个字节(包括分隔符)。

  

即使我通过分配运行我的代码   像4GB的内存,我仍然用完了   堆空间。我错过了什么?

这取决于您的代码。一个原因可能是您将数据存储在ArrayList<Double>或(更糟)TreeSet<Double>中 - Double包装器对象将导致内存开销容易200% - 而Set /地图结构要糟糕得多。

答案 3 :(得分:0)

很难说没有看到代码和VM参数。但请注意,算法中的变量也会消耗内存。文件大小与内存使用量的关系取决于构建内存中对象的方式,例如,没有double的简单对象会占用空间。

获取用于对内存使用情况进行基准测试的适当工具。查看TPTP Eclipse distribution

另外,您可能想查看sparce matrixes

答案 4 :(得分:0)

如果我们看不到代码(这是公平的),我可以说的是在启动应用程序时使用-XX:+HeapDumpOnOutOfMemoryError命令行选项,然后使用{{1分析生成的堆转储}}

相关问题