代码之家  ›  专栏  ›  技术社区  ›  Brad Mace Mike King

用于内存高效数据存储的HashMap替代方案

  •  26
  • Brad Mace Mike King  · 技术社区  · 14 年前

    我现在有一个电子表格类型的程序,它将数据保存在哈希映射的ArrayList中。当我告诉你这还不太理想时,你肯定会大吃一惊。开销似乎比数据本身占用的内存多5倍。

    This question 当被问及高效的收藏库时,答案是使用Google collections。 我的后续行动是“ 哪部分? . 我一直在阅读这些文档,但我不认为它能很好地说明哪些类适合这样做。(我也接受其他图书馆或建议)。

    所以我正在寻找一种能让我以最小的内存开销存储密集的电子表格类型数据的方法。

    • 我的列当前由字段对象引用,行由其索引引用,值是对象,几乎总是字符串
    • 有些列将有很多重复值

    我知道H2和Derby这样的选项,但在本例中,我不打算使用嵌入式数据库。

    :如果您建议使用库,如果您能给我指出其中一两个特定的类,我也会非常感激。Sun的文档通常包含关于哪些操作是O(1)、哪些是O(N)等的信息,但我在第三方库中没有看到太多这方面的内容,也没有任何关于哪些类最适合什么的描述。

    10 回复  |  直到 8 年前
        1
  •  4
  •   Steve B.    14 年前

    所以我假设你有一张 Map<ColumnName,Column> ,其中列实际上类似于 ArrayList<Object>

    一些可能性-

    • 你完全确定记忆是个问题吗?如果你只是一般担心大小,这是值得确认的,这将是一个真正的问题,在运行的程序。填充JVM需要大量的行和映射。

    • 如何将数据存储在一个类似于矩阵的数据结构(现有的库实现或类似于列表列表的包装)中,使用一个将列键映射到矩阵列的映射呢?

        2
  •  12
  •   Brian Agnew    14 年前

    有些栏目会有很多

    立即建议我使用 FlyWeight pattern

        3
  •  5
  •   Jack    14 年前

    收藏 应该特别注意占用的空间(如果您坚持使用基本类型,我认为它们还具有定制的数据结构)。。看一看 here .

    否则你可以试试 Apache collections .. 做你的基准!

    不管怎样,如果有很多对相同元素的引用,请尝试设计一些合适的模式(比如 flyweight )

        4
  •  3
  •   Peter Lawrey    14 年前

    如果字符串经常重复,可以使用字符串池来减少字符串的重复。其他不可变类型的对象池可能有助于减少内存消耗。

    编辑: 您可以将数据结构为基于行或基于列。如果它基于行(每行一个单元格数组),则添加/删除行只是删除此行的问题。如果它基于列,则可以为每列设置一个数组。这可以使处理原始类型更加有效。i、 e.可以有一列是int[],另一列是double[],对于整列来说,更常见的是具有相同的数据类型,而不是对于整行具有相同的数据类型。

    但是,无论您以何种方式构造数据,都将对其进行行或列修改,并且执行其他类型的添加/删除操作将导致整个数据集的重新生成。

    (我要做的是使用基于行的数据并在末尾添加列,假设行不够长,则该列具有默认值,这样可以避免在添加列时重新生成。与其删除列,我有办法忽略它)

        5
  •  2
  •   whiskeysierra    14 年前

    Table 接口和基于哈希的实现。似乎很适合你的问题。请注意,这仍然标记为beta。

        6
  •  2
  •   Community CDub    8 年前

    Chronicle Map 每个条目的开销可能小于20字节(请参见 a test -XX:+UseCompressedOops 到58-69字节,无压缩oops( reference

    另外,Chronicle映射将键和值存储在堆外,因此它不存储对象头,而对象头不计入上面HashMap的开销。编年史地图 integrates 具有 Chronicle-Values suggested by Brian Agnew 另一个答案。

        7
  •  1
  •   Nikita Rybak    14 年前


    嗯,我觉得这部分效率太低了。空HashMap将已分配 16 * size of a pointer

    一种选择是使用一个带有复合键的大型散列(组合行和列)。不过,这并不能使整行的操作非常有效。

    另外,由于您没有提到添加单元格的操作,因此可以只使用必需的内部存储创建散列( initialCapacity 参数)。

        8
  •  1
  •   Brad Mace Mike King    14 年前

    我一直在尝试使用 SparseObjectMatrix2D Colt 项目。我的数据非常密集,但它们的矩阵类并没有提供任何放大它们的方法,所以我使用了一个稀疏矩阵集,将其设置为最大大小。

    对于相同的数据,它使用的内存大约减少了10%,加载速度提高了15%,并且提供了一些聪明的操作方法。但仍对其他选择感兴趣。

        9
  •  0
  •   leonbloy    14 年前

    ArrayList的(链接)哈希映射 (每个ArrayList都是一列)。

    我将添加一个从字段名到列号的双映射,以及一些从不抛出 IndexOutOfBoundsException .

    你也可以使用 ArrayList<ArrayList<Object>> (基本上是一个锯齿状的数据增长矩阵)并保持到外部字段(列)名称的映射。

    重复值

    我怀疑这一点,特别是如果它们是字符串(它们是内部化的),并且您的集合将存储对它们的引用。

        10
  •  0
  •   NiranjanBhat    12 年前

    为什么不尝试使用如下缓存实现 EHCache 当我遇到同样的情况时,这对我来说非常有效。
    您只需将集合存储在EHcache实现中。

    Maximum bytes to be used from Local heap.
    

    一旦应用程序使用的字节溢出缓存中配置的字节,那么缓存实现将负责将数据写入磁盘。还可以使用最近使用的算法配置对象写入磁盘的时间量。 使用这种类型的缓存实现,可以确保避免任何内存不足错误。 它只会稍微增加应用程序的IO操作。