【问题标题】:Memory efficiency: HashMap versus Array内存效率:HashMap 与 Array
【发布时间】:2014-02-20 13:11:19
【问题描述】:

我在考虑以下情况:我想计算字符串中字符的出现次数(例如用于排列检查)。

一种方法是分配一个包含 256 个整数的数组(我假设字符是 UTF-8),用零填充它,然后遍历字符串并在对应的数组位置上递增整数到字符的 int 值。

但是,对于这种方法,您每次都必须分配一个 256 个数组,即使分析的字符串非常短(因此只使用数组的一小部分)。

另一种方法是使用 Character 到 Integer HashTable 并为每个遇到的 char 存储一个数字。这样,您将只有实际在字符串中的字符的键。

由于我对 HashTable 的理解是理论上的,而且我真的不知道它是如何在 Java 中实现的,所以我的问题是:这两种方法中哪一种更节省内存?

编辑:

在讨论这个问题的过程中(谢谢大家的回答),我确实意识到我对 UTF-8 的性质有一个非常模糊的理解。经过一番搜索,我找到了我想分享的this great video,以防有人遇到同样的问题。

【问题讨论】:

  • 我曾经拥有一台内存高达 56K 的 Apple II。我也曾经每天步行 5 英里上学,双向上山…… :) 也许那时我会担心 256 个整数的数组。
  • 如果最小的 HashMap 占用的存储空间少于 256 个整数的数组,我会感到相当惊讶
  • 问题的约束是如何准确定义的? UTF-8 目前支持表示大约 250,000 个不同的字符。
  • 可能有超过一百万,实际上分配给当前规范中的真实角色是不同的:)
  • 有些字符集(例如 latin-9)可编码为 8 位并涵盖(西方)“欧洲语言”。在实践中,对于大多数现实世界的数据,即使只是 € 也将具有 8364 的十进制编码。您愿意分配多大的数组?地图突然变得更好了!

标签: java arrays hashtable


【解决方案1】:

我会使用数组。从性能方面来看,您可以保证持续访问。比散列表所能得到的更好。

由于它也只使用固定数量的内存,我认为没有缺点。 HashMap 很可能需要更多内存,即使您只存储几个元素。

顺便说一句,内存占用不应该是一个问题,因为您只需要数据结构,只要您需要它进行计数。无论如何,它将被垃圾收集。

【讨论】:

    【解决方案2】:

    初始化一个表示char的int值的整数数组,例如f的int值是102,也就是它的ascii值

    http://www.asciitable.com/

    char c = 'f';
    int x = (int)c;
    

    如果你知道你要处理的字符的范围,那就更容易了。

    对于每次出现的 char 将数组中该 char 的索引增加一。如果您必须进行迭代,这种方法会很慢;如果您要进行排序,这种方法会很复杂,但不会占用大量内存。

    请注意,在排序时会丢失索引

    【讨论】:

      【解决方案3】:

      无需查看代码,我就知道 HashMap 至少需要一个基础对象、一个哈希表数组以及每个哈希条目的单独对象。通常,一个 int 值必须存储为一个 Integer 对象,这样就有更多的对象。假设您有 30 个独特的字符:

      • 32 字节用于基础对象
      • 256 字节的最小大小哈希表数组
      • 30 个表条目,每个条目 32 个字节
      • 30 个整数中的每一个 16 个字节(如果高度优化)

      32 + 256 + 960 + 480 = 1728 字节。这是一个最小的、非花哨的实现。

      256 个整数的数组大约是 1056 个字节。

      【讨论】:

        【解决方案4】:

        当您假设您的字符串是 UTF-8 时,我想知道为什么您选择 256 作为数组的长度。在 UTF-8 中,一个字符最多可以由 4 个字节组成,这意味着比 256 个字符多得多。

        无论如何:使用 HashTable/HashMap 需要巨大的内存开销。首先,您的所有字符和整数都需要包装在一个对象(整数/字符)中。 Integer 消耗的内存大约是 int 的 3 倍。对于数组,由于 java 对数组执行的优化,差异可能更大(例如,java 堆栈只能以 4 字节的倍数工作,而在数组中,java 允许较小的类型(例如 char)仅消耗 2 个字节)。

        那么 HashTable 本身会产生内存开销,因为它需要维护一个数组(通常没有完全使用)和链表来维护所有生成相同哈希的对象。

        此外,数组的访问时间将大大加快。您保存了多个方法调用(add、hashCode、iterator...),并且在 java 字节码中存在许多操作码,以使处理数组更有效。

        无论如何。你的问题是:

        这两种方法中哪一种更节省内存?

        可以肯定地说,数组的内存效率会更高。

        但是,您应该绝对确定您的要求是什么。您需要更高的内存效率吗? (如果您处理大量数据或使用速度较慢的设备(移动设备?)可能是真的)代码的可读性有多重要?代码大小如何?可重用性?

        而且 ist 256 的大小真的正确吗?

        【讨论】:

          【解决方案5】:

          这是事实。

          • HashMap 在后台使用数组作为其表。

          所以如果你真的受限于在内存中寻找一个连续的空间,HashMap 的好处只是数组可能更小。

          • HashMap 是通用的,因此使用对象。

          对象占用额外空间。我记得,它通常最少 8 或 16 个字节,具体取决于它是 32 位还是 64 位系统。这意味着 HashMap 可能不会更小,即使 String 中的字符数很少。 HashMap 需要为每个条目添加 3 个额外的对象:EntryCharacterInteger。 HashMap 还需要在本地存储索引的 int,而数组不需要。

          除此之外,还会使用 HashMap 进行一些额外的计算。

          我还要说空间优化不是您应该担心的事情。无论哪种方式,内存占用实际上都非常小。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-05-09
            • 1970-01-01
            • 2023-03-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多