【问题标题】:How much memory does the biggest possible array need?最大可能的数组需要多少内存?
【发布时间】:2021-03-19 18:30:08
【问题描述】:

我想获得在 Java 中创建最大可能数组所需的确切内存量。

我的测试程序:

public class MemoryOfArraysTest {
    public static void main(String... args) {
        Object[] array = new Object[Integer.MAX_VALUE - 2];
    }
}

我通过自己的测试知道数组的最大长度是Integer.MAX_VALUE - 2 (2147483645)。

如果数字更大,您将收到以下错误:

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
at MemoryOfArraysTest.main(MemoryOfArraysTest.java:3)

但这只是接近数组最大长度的一步。另一个问题是您的 VM 可以使用的内存。您可以使用-Xmx 指定内存。

如果我使用java -Xmx1g MemoryOfArraysTest(只有 1GB 内存)运行我的课程,我会收到预期错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at MemoryOfArraysTest.main(MemoryOfArraysTest.java:3)

如果我使用java -Xmx10g MemoryOfArraysTest(10GB 内存)运行它,它就可以工作。

这是我目前所拥有的。但是我的程序需要的确切内存量是多少?最好在 KB 中。有没有办法计算?

【问题讨论】:

  • 这是一个非常酷的概念,但是为什么?
  • Integer.MAX_VALUE - 2 == 数组中的 2147483646 个元素。在具有-XX:+UseCompressedOops(默认值)的 64 位 VM 上,引用占用 4 个字节。目前 OpenJDK 上的数组头占用 16 个字节(stackoverflow.com/questions/17335884/…,注意 Zing 和 OpenJ9 可以不同,项目 Lilliput 最终会出现),所以 2147483646 * 4 + 16 个字节。但为什么?这很少需要知道。你在解决什么问题,你想达到什么目标?
  • 实际上不可能找出来。或者至少,这是不可行的。您无法知道类加载器加载的其他类占用了多少堆空间(例如所有 java.lang 废话)。在不知道这一点的情况下,您无法知道还剩下多少堆空间。默认情况下加载的东西所使用的确切堆数量在几乎每个 JDK 构建之间都会略有不同。
  • 旁注:可能的最大数组是long[]double[],因为每个条目将占用64 位或8 字节。使用最大可能的数组大小 (Integer.MAX_VALUE = 2^31 - 1) 进行计算会产生略高于 16 GB (17179869192 字节) 的大小
  • 当然它没有真正的用例。我不是想创建一个这样长度的数组。我真的很想知道一个方程是什么以及在 Java 中一般如何管理数组。但我认为这样问不会得到回答。因为我的问题不会很清楚。感谢所有提供答案的cmets。它们帮助我更多地理解记忆的主题。

标签: java arrays memory


【解决方案1】:

每个对象有两个标题,XX:+UseCompressedOops(默认开启),这两个标题将有12 bytes。加上4 bytes 来保持数组的长度。加上一些您还需要考虑的最终填充。

您可以使用JOL 了解它有多大。像这样的实验:

    Object[] array = new Object[100];
    for(int i=0;i<100;++i){
        array[i] = new Object();
    }

    System.out.println(GraphLayout.parseInstance(array).totalSize());

显示它有1600 bytes。如果我将该大小更改为1000,我将得到16000 bytes

但是通过数学计算,您可以说Object[2147483646] 的大小将在34 GB 左右。


请注意,填充该数组与不填充该数组之间存在很大差异。如果未填充:

Object[] array = new Object[Integer.MAX_VALUE - 2];
System.out.println(ClassLayout.parseInstance(array).instanceSize()); 

它会很重 8GB

【讨论】:

  • 我的 Mac 上有 32 GB 的 RAM,即使我尝试增加交换,我的 Mac 也会在尝试计算该大小的填充数组时关闭
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多