我有一个数据集保存为文本文件,基本上包含逐行存储的向量。我的向量是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的内存来运行我的代码,我仍然会耗尽堆空间。我错过了什么?
感谢。 安迪
答案 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
)足以运行测试。
所以我猜问题不是大小,可能是两件事:
如果有人对代码感兴趣:
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分析生成的堆转储}}