【问题标题】:Array vs Matrix in terms of memory in Java数组与矩阵在 Java 中的内存
【发布时间】:2015-01-22 07:09:14
【问题描述】:

我正在从事一个涉及启发式的项目,并且我用 Java 构建了它(应该用 C 语言构建它)。 我遇到了内存问题。

我的树由对象节点组成,每个对象包含一个数组、一个矩阵和三个整数。 我已经削减了许多其他值,以尝试节省更多的内存空间,但是仍然不够。

所以,我在想我也可以削减矩阵,并将其转换为数组。 但是,我的整个项目都是建立在坐标上的,以达到矩阵中的某个点。 因此,在进行任何更改之前,我想知道这会影响内存使用多少(或不影响多少)。

编辑:数组和矩阵都由 int 基元组成。

数组是array[25],矩阵是matrix[5][5]。

矩阵代表游戏的棋盘,包含字段是否为空,或者里面是否有某种类型的棋子的信息(全是int)。

我说的是 16GB 的 RAM 使用量和 2500 万个节点。

我做了这个方法,用来克隆数组:

public int[] cloneArray(int[] array){
    int i = 0;
    int[] clone = new int[array.length];
    while (i < array.length){
        clone[i] = array[i];
        i++;
    }
    return clone;
}

我们使用了类似的方法来克隆矩阵和对象本身。

编辑: 在发现探查器的存在后,我进行了检查。 这是结果的屏幕截图:

我认为这些数字是有道理的,因为在控制台中,您可以看到几乎与在分析器中看到的一样多的节点,状态(在控制台中,“estados”是状态的指针目前正在扩展中)。

因此,在分析器中,我们可以看到将近 20m 个状态,它们是生成的节点。 每个状态包含 1 个数组和 1 个矩阵。

我们可以看到 138m 的数组,除以 6 等于 23m。 并且由于一个矩阵是5x5的,那么5x23m的数组包含在矩阵中,另外23m是数组。

我说得有道理吗?这种解释准确吗?

这是一个 Dropbox 链接,您可以查看完整分辨率的图片: https://www.dropbox.com/s/7wxz8vch1wnrsyr/Untitled.png?dl=0

【问题讨论】:

  • “矩阵”是二维数组还是自定义对象?
  • 一个数组会阻塞所有分配给它的内存,所以当你创建一个二维数组时,整个空间都会被占用——如果你有一个稀疏的数组,这会阻塞更多的内存,是的.
  • “应该是用 C 语言实现的” - 如果你还用c 标记了你的问题,同时说这个你的问题可能已经收到了几个赞成票:)
  • 如果你有这么多节点,我猜使用一维数组而不是二维数组可能会有所不同,因为正确获取索引很容易出错。另一方面,如果您的 RAM 如此紧张,您可能很容易再次遇到麻烦
  • @WilhelmSorban en.wikipedia.org/wiki/Sparse_matrix 是的,与一维数组相比,二维数组具有额外的开销,因为二维数组实际上是一个数组数组,因此对于您拥有的每一行常见的“数组开销”。

标签: java c arrays matrix


【解决方案1】:

这里有几个例子:

int[] array = new int[25];

int[][] matrix = new int[5][5];

数组占用的空间为:

  • 25 x 4 字节整数(数组内容)
  • 12 字节的数组对象头
  • 共 112 个字节

Java中一个二维的int矩阵其实是一个数组数组,所以矩阵占用的空间是

  • (5 x 4 字节整数 + 12 字节数组头)x 5。
  • 5 x 4 字节引用 + 12 字节数组头
  • 共 192 个字节

(以上假设 32 位 JVM 和 典型 数组标头大小。这些是特定于平台的假设,但对于任何 JVM 平台,您应该能够将它们与特定性联系起来。对于 Oracle从 Java 6 开始的 HotSpot / OpenJDK JVM,任何人都可以查看源代码。)

当然请注意,随着数组/矩阵变大,int[N^2]int[N][N] 的相对节省会变小。

【讨论】:

  • 快速提问,斯蒂芬。为什么数组头有 12 个字节?您可以看到我在 cmets 中的计算略有不同 - 我有 4 个字节用于数组头。除了单个地址之外,标头中还有什么?
  • @DavidWallace 见this answer。本质上,一个词用于数组的类引用,一个用于同步和垃圾回收标志,一个用于大小。
  • 感谢@PatriciaShanahan,这一切都说得通。此外,有趣的是,这是 64 位 JVM 上的 20 或 24 字节。这确实开始加起来了。
  • 在我看来,在 64 位 JVM 上,一维数组的 124 字节和二维数组的 284 字节很容易;每个节点总共 420 字节,为 2500 万个节点提供 10.5GB。
  • 我添加了分析器统计数据的屏幕截图和一些详细信息。你能检查一下它是否准确吗?
【解决方案2】:

您的问题可能暗示代码中存在隐藏问题,而不是“内存不足问题”。堆内存没有这么快完成,你需要你的代码非常重才能到达那里。

不过,我敢说将二维矩阵更改为数组不会对内存使用量产生太大影响。 说到哪 - 实现高维数组(2 及以上)的 2 种最常见的方法是 1)将其切片为一维数组,然后使用公式:

arr[a][b].. = arr[a+b+..]

2) 使用指向指针的指针,然后你得到一个指针数组,它指向另一个指针数组,依此类推,直到最后一级是真实对象

这就是说,(再次,大胆),Java 可能已经在幕后将矩阵分割成一维数组。

无论如何,我高度怀疑您的代码中存在内存泄漏,或者没有结束递归,或者上述情况的组合。在尝试实施您的建议之前尝试看看您不在那里。

【讨论】:

  • 我怀疑我有内存泄漏,因为当我从构造函数中删除了另一个数组和一个矩阵时,可以生成的节点几乎翻了一番。
  • "由于 Java 是一种托管代码语言,而 Oracle JVM 代码不是开放的,我们无法 100% 回答 java 如何运行内存,或者它进行了哪些优化在代码上做。” 这是垃圾。核心 JVM 和 GC 的源代码都是开源的。 AFAIK,您无法获得的唯一源代码是您需要付费许可证才能启用的“特殊内容”。
猜你喜欢
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-09
  • 2010-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多