用于存储大量长值列表的数据结构

时间:2013-02-12 07:38:35

标签: java performance caching data-structures

我在我的Java程序中缓存Long索引列表,导致内存溢出。 因此,决定只缓存所有连续索引的开始和结束索引,并重写ArrayList所需的API。现在,在这里实现起始端索引缓存的最佳数据结构是什么?是否更适合使用TreeMap并将起始索引作为键和结束索引保持为值?

3 个答案:

答案 0 :(得分:0)

如果我是你,我会使用一些变量的位串存储。

在Java中,位字符串由BitSet实现。

例如,要表示唯一的32位整数列表,可以将其存储为40亿位长的单个位串,因此需要4 bln / 8位= 512 MB的内存。这很多,但它是最糟糕的情况

但是,你可以比这更聪明。例如,您可以将其存储为一些较小的固定(或动态)大小的位串的列表或二叉树,例如65536位或更少(或8KB或更少)。换句话说,此树中的每个叶对象将具有表示起始偏移和长度的小标题(为简单起见,可能是2的幂,但不一定是),以及存储实际数组成员的位串。为了提高效率,您可以选择使用gzip或类似算法压缩此位字符串 - 它会使访问速度变慢,但可以将内存效率提高10倍或更多。

如果您的2000万个索引元素几乎是连续的(不是很稀疏),那么它应该只需要大约20mln / 8bits~ = 2百万位= 2 MB来表示它在内存中。如果你gzip它,整体可能不到1MB。

答案 1 :(得分:0)

最紧凑的表示形式将在很大程度上取决于特定应用程序中索引的分布。

如果你的索引是密集聚类的,那么mvp建议的基于范围的表示可能会很好用(你可能会看一下栅格图形的游程编码实现,因为它们是类似的问题)。

如果您的索引没有在密集运行中聚集,那么该编码实际上会增加内存消耗。对于稀疏填充的列表,您可以查看原始数据结构,例如FastUtil中的LongArrayList或LongOpenHashSet,或Gnu TroveColt中的类似结构。在大多数虚拟机中,ArrayList中的每个Long对象消耗20多个字节,而原始长度仅消耗8个。因此,您通常可以使用特定于类型的原始集合而不是标准集合框架来节省大量内存。

我对FastUtil非常满意,但您可能会发现另一种解决方案更适合您。一点模拟和内存分析应该可以帮助您确定自己数据的最有效表示。

答案 2 :(得分:0)

大多数BitSet(压缩或未压缩)实现都是针对整数的。这是一个longs:http://www.censhare.com/en/aktuelles/censhare-labs/yet-another-compressed-bitset,它的作用类似于有序的原始长哈希集或长到长的哈希映射。