【问题标题】:how calculate java array memory usage如何计算java数组内存使用量
【发布时间】:2011-02-27 16:35:56
【问题描述】:

如果我有:

int c[] = new int[10];

int a[][] = new int[2][3];

一般来说

n*m*..*j 数组

如何在考虑引用变量的情况下计算实际内存使用量?

【问题讨论】:

  • 获得这些数组的“实际内存使用情况”是否有动机?

标签: java arrays


【解决方案1】:

我知道我参加聚会有点晚了,但计算内存占用量真的不是特别难。

让我们举第一个例子:int c[] = new int[N];

根据 64 位内存模型,一个 int 是 4 个字节,所以所有元素的大小都是 4*N 字节。除此之外,Java 有 24 字节的数组开销,实际的数组对象也有 8 字节。所以总共是 32 + 4 * N 字节。

对于二维数组:int a[][] = new int[N][M];

基本相同,只是第一个数组中的每个元素都是另一个大小为 M 的数组,所以我们用 32 + 4 * M 代替 4,所以总大小是 32 + (32 + 4 * M) * N .

确实,D 维度的概括非常复杂,但你明白了。

【讨论】:

  • 你从哪里得到 24 字节的开销?我假设这个数字是针对某些特定的虚拟机的。
  • 这是我需要的答案。我正在做一个项目,我需要一个非常大的数组,我不想把它分解成一堆磁盘操作,我需要知道这些对象将消耗多少内存。谢谢。
【解决方案2】:

如果你想要一个准确的答案,你不能。至少不是以任何简单的方式。 This thread 解释更多。

Bragaadeesh 和 Bakkal 的答案的问题在于他们忽略了开销。每个数组还存储诸如维数、长度以及垃圾收集器使用的一些内容。

对于一个简单的估计,您应该可以使用其他答案的计算并添加 100-200 字节。

【讨论】:

  • 这个答案是正确的。由于类型/ GC 信息等等,总会有开销。此外,Java 没有真正的多维数组,只有锯齿状数组,这最终会产生相当多的开销。
  • 多维数组在内存中如何表示?
  • 我删除了我的答案,因为我不知道如何计算包含开销的 exact 大小。
  • @xdevel2000:Java 没有多维数组。只有数组的数组。
  • @Matti Virkkunen:是的。 VM 仍然会跟踪嵌套了多少层数组,因此您不能将一个字符数组分配给一个字符数组。
【解决方案3】:

您可能会从中得到最好的近似值:http://java.sun.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html#getObjectSize(java.lang.Object)

这个article 和这个comprehensive one 演示/详细说明了这种方法

【讨论】:

    【解决方案4】:

    int[]int[][] 不是原始数据类型。它是Java中的一个对象。并且对于 Object,无法立即计算大小。

    【讨论】:

    • +sizeof(int) 来自哪里?
    • 引用可能不是 4 个字节,具体取决于您的平台。
    • @Matti:同意。整个事情都不正确。让我编辑一下。
    • 将参考内存写为sizeof(int) 会产生误导,即使在特定平台上它是 4 个字节。
    • 我认为,如果我们继续编辑以使其在技术上正确,我们将接受“没有简单准确的方法”:P
    【解决方案5】:

    我知道这是一个老问题,但我也有同样的问题,并且此线程中提供的信息对我没有帮助。给我所需信息的来源:https://www.javamex.com/tutorials/memory/array_memory_usage.shtml

    这是我的情况:我有一个大数组

    int a[][] = new int[m][n];
    

    “大”实际上具有误导性:m 很大 (3^18 = 387420489) 但 n 很小 (4)。我一直遇到我不理解的内存问题,因为 m * n * 4 = 6198727824 (~6GB) 而我有 16GB 的 RAM(并且 JVM 允许使用 -Xmx12G 有 12 个)。我刚才放的链接给了我答案:

    10 行中的每一行都有自己的 12 字节对象头,4*10=40 字节用于实际的整数行,同样,4 字节的填充使该行的总数达到 8 的倍数

    这就是我的二维数组的内存明显偏离4 * m * n的地方:这里,因为n很小(4),所以每一行的大小确实不同于4 * n;如果你应用链接中给出的公式(即使它是近似的),你会得到,对于每一行:12(标题)+ 4 * 4(四个整数)+ 4(填充到 8 个字节的倍数)= 32。这是我预期成本的两倍,并说明我遇到了内存溢出。

    【讨论】:

      【解决方案6】:

      对于原始类型:字节的基本类型和大小

      • 布尔值 1
      • 字节 1
      • 字符 1
      • int 4
      • 浮点数 4
      • 长8
      • 双8
      • 整数 24(16 用于 Class 实例 + 4 用于 int + 4 用于内存对齐)

      int a[M]:24+4M

      (Class 16 + 保存数组大小 4 + 内存对齐 4) + (对于 double 的 M 大小,我们需要 4 * M)

      int a[M][N]: (24+4M) + M*(24+4N) = 24+28M+4MN ~~~4MN

      将 a[M][N] 视为 M 大小的双数组 a[N] 加上一个额外的数组来保存所有 M 大小数组起点的引用。

      【讨论】:

      • 当你在讨论不同的类型时,我们可能有不同的大小,但是对于int,我们可以进行计算(由于内存对齐可能会有一些差距)
      • M = ?,数组总是声明为int...这个答案可以改进。
      【解决方案7】:

      Yann 上面的回答是正确的,我通过堆转储仔细检查了它。

      这是我们计算数组的确切内存大小所需的数据(来源:https://www.javamex.com/tutorials/memory/array_memory_usage.shtml):

      • Java 选择的类型大小(例如:double = 8 字节)'S'
      • Java 数组四舍五入为:8 字节“q”的倍数
      • Java 参考大小:4 字节“R”
      • Java 数组标头大小:12 字节“H”

      公式:

      对于一个 double[N] = (N * S + H) + (N * S + H) % q = 'x'

      对于双[M][N] = [M * (x + R) + H] + [M * (x + R) + H] % q = 'y'

      举个例子:

      double[10] = (10 * 8 + 12) + (10 * 8 + 12) % 8 = 96 字节

      双[10][10] = [10 * (96 + 4) + 12] + [10 * (96 + 4) + 12] % 8 = 1016 字节

      简单地乘以底层原始类型(错误)会产生:

      双[10] = 8 * 10 = 80 字节

      双[10][10] = 8 * 10 * 10 = 800 字节

      【讨论】:

        猜你喜欢
        • 2011-09-03
        • 2016-10-21
        • 1970-01-01
        • 1970-01-01
        • 2018-01-18
        • 2020-12-07
        • 1970-01-01
        • 2013-03-31
        相关资源
        最近更新 更多