2

我正在尝试创建一个二维数组,如下所示。

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");
   }
}
4

2 回答 2

2

每个数组都有一个开销(例如,请参阅有关其开销的 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] ;” 这也应该起作用(开销较小)。

我知道这不会解决您的问题 - 但我希望这能让您对开销有所了解。

于 2013-02-01T09:29:20.657 回答
1

我检查了 Harmony JVM 中的对象布局(我想 JVM 的其他实现类似)。java中的每个Object都有一个对象头,其中包含JVM的重要信息。最重要的是对对象类的引用(一个词)。此外,GC 使用了一些标志来管理同步,即锁定字(因为每个对象都可以同步)占用另一个(使用部分字对性能不利)。所以这是 2 个字,在 32 位系统上是 8 个字节,在 64 位系统上是 16 个字节。数组还需要一个 int 字段来表示数组长度,即另外4 个字节,可能是8 个字节在 64 位系统上。所以对于每个数组,在 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%。

于 2013-02-01T08:03:17.223 回答