我正在尝试创建一个二维数组,如下所示。
int NUM_RECORDS = 100480507;
byte[][] completeArray = new byte[NUM_RECORDS][6];
拥有这还不够吗
100480507 * 6 ~= 0.6 GB
另请参阅这个问题。
但是创建这个数组会耗尽内存。我已经通过 JVM args 为我的 java 进程分配了 4G。
这该如何解释呢?我在这里错过了一些微不足道的事情吗?
这是我的程序
public class MemTest {
public static void main(String[] args) {
int NUM_RECORDS = 100480507;
byte[][] completeArray = new byte[NUM_RECORDS][6];
System.out.println("Array created");
}
}
每个数组都有开销(例如,请参阅有关其开销的 IBM 文档 -> http://www.ibm.com/developerworks/java/library/j-codetoheap/index.html)。在你的例子中,你正在创建 100480507 个!
如果您将代码更改为“byte[]completeArray = new byte[NUM_RECORDS*6];”,根据您的理论,它应该需要相同的空间!但是,我相当确定这会起作用,因为开销最少。您也可以尝试“byte[][]completeArray = new byte[6][NUM_RECORDS];”这也应该有效(开销较小)。
我知道这不会解决您的问题 - 但我希望这能让您对开销有一些看法。
我检查了 Harmony JVM 中的对象布局(我想 JVM 的其他实现也类似)。 java中的每个对象都有一个对象头,其中包含JVM的重要信息。最重要的是对对象类的引用(一个词)。此外,GC 使用一些标志来管理同步,即锁字(因为每个对象都可以同步),它占用另一个“一个字”(使用部分字会降低性能)。所以这是 2 个字,在 32 位系统上是 8 个字节,在 64 位系统上是 16 个字节。数组还需要一个 int 字段来表示数组长度,这在 64 位系统上又是 4 字节,可能是 8 字节。因此,对于每个数组,在 32 位机器上我们有 12 个额外字节,在 64 位机器上可能有 24 个字节。 在你的程序中,你有 6 个数组。 100480507 一维数组。所以额外的内存消耗大约是1.2 + 0.6 GB,这是一个非常大的连续内存块。开销约为200%。
当我们将代码更改为:
public class MemTest {
public static void main(String[] args) {
int NUM_RECORDS = 100480507;
byte[] completeArray = new byte[NUM_RECORDS * 6];
System.out.println("Array created");
}
}
我们只创建1个数组,因此开销非常小。总共约0.6GB。
当代码更改为:
public class MemTest {
public static void main(String[] args) {
int NUM_RECORDS = 100480507;
byte[][] completeArray = new byte[NUM_RECORDS][6];
System.out.println("Array created");
}
}
我们总共有 7 个数组。该计划将立即结束。
在您的代码风格中创建另一个 0.6GB 内存,但将元素类型从 int 更改为 long:
public class MemTest {
public static void main(String[] args) {
int NUM_RECORDS = 12560063;
long[][] completeArray = new long[NUM_RECORDS][6];
System.out.println("Array created");
}
}
程序也可以立即结束。开销约为150M/600M = 25%。