我正在尝试创建一个2D数组,如下所示。
int NUM_RECORDS = 100480507;
byte[][] completeArray = new byte[NUM_RECORDS][6];
拥有100480507 * 6 ~= 0.6 GB
同时查看this问题。
但是这个数组的创建耗尽了内存。我已经通过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");
}
}
答案 0 :(得分:2)
每个数组都有开销(例如,请参阅IBM文档中的开销 - > http://www.ibm.com/developerworks/java/library/j-codetoheap/index.html)。在您的情况下,您正在创建100480507!
如果您将代码更改为“ byte [] completeArray =新字节[ NUM_RECORDS * 6 ];”,根据您的理论,它应该需要相同的空间!但是,我相当肯定这会起作用,因为开销最小。您也可以尝试“byte [] [] completeArray = new byte [6] [NUM_RECORDS] ;”这也应该有效(开销较小)。
我知道这不会解决您的问题 - 但我希望这会让您对开销有所了解。
答案 1 :(得分:1)
我检查Harmony JVM中的对象布局(我猜想JVM的其他实现类似)。 java中的每个Object都有一个对象头,其中包含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%。