Java 内存优化 [Key:Long, Value:Long] 存储非常大 (500M) 用于并发读取访问

0 java collections apache-commons guava

我有一个用例,我需要存储大约大小的键 - 值对。大小为 8 GB 的单个 VM 中的 5 亿个条目。Key 和 Value 属于 Long 类型。键从 1、2、3 开始自动递增,依此类推。

仅当我在程序开始时构建这个 Map[KV] 结构作为独占操作,一旦构建,仅用于查找,在此结构中不会执行更新或删除。

我已经用 java.util.hashMap 尝试过这个,但正如预期的那样,它消耗了大量内存并且程序给 OOM:堆使用超过错误。

我需要一些有关以下方面的指导,这有助于减少内存占用,我对访问性能有所下降感到满意。

  1. 可以在此处尝试的其他替代方法是什么(来自 java 集合或其他库)。
  2. 出于比较目的,通过此 Map 获取内存占用的推荐方法是什么。

Ste*_*n C 5

只需使用long[]long[][]

5 亿个升序键小于 2^31。如果超过 2^31,请使用long[][]第一个维度小而第二个维度大的地方。

(当键类型为整数时,如果键空间稀疏,则只需要复杂的“映射”数据结构。)

一维阵列中的空间浪费是微不足道的。每个 Java 数组节点都有 12 字节的头,节点大小四舍五入为 8 字节的倍数。因此,5 亿个条目long[]将需要接近 5 亿 x 8 字节 == 40 亿字节,这无关紧要。

但是,JVM 通常无法分配占用整个可用堆空间的单个对象。如果虚拟地址空间非常宝贵,建议使用二维数组;例如new long[4][125_000_000]。这会使查找稍微复杂一些,但这样做很可能会减少内存占用。


如果您事先不知道预期的键数,您可以使用数组和ArrayList对象的组合来做同样的事情。但是ArrayList有一个问题,如果你不设置一个(准确的)容量,内存利用率很可能是次优的。如果您ArrayList通过追加来填充 an ,则 的瞬时内存需求append可能是列表当前空间使用量的 3 倍。