Java BitSet
在内存中,并且没有压缩。
假设我在位图中有10亿个条目 - 内存占用125 MB。 假设我必须在10个这样的位图上执行AND和OR操作,它需要1250 MB或1.3 GB内存,这是不可接受的。 如何在这些位图上进行快速操作而不将它们在内存中保持未压缩状态?
我不知道位集中位的分布。
我还使用行程编码(RLE)压缩查看了JavaEWAH,这是Java BitSet
类的变体。
有没有更好的解决方案?
答案 0 :(得分:2)
一种解决方案是使阵列远离堆。
您想通过@PeterLawrey阅读this answer相关问题。
总之,Java中的内存映射文件的性能非常好,它避免了在堆上保留大量对象。
操作系统可能会限制单个内存映射区域的大小。通过映射多个区域,可以轻松解决此限制。如果区域是固定大小,则可以使用实体索引上的简单二进制操作在内存映射文件列表中查找相应的内存映射区域。
你确定需要压缩吗?压缩将交换空间的时间。减少的I / O最终可能会节省您的时间,但它也可能无法实现。你能加一个SSD吗?
如果您还没有尝试过内存映射文件,请从此开始。我将密切关注在彼得的纪事报之上实施某些事情。
如果您需要更高的速度,可以尝试并行执行二进制操作。
如果你最终需要压缩,你总是可以在Chronicle的内存映射数组之上实现它。
答案 1 :(得分:0)
从这里的评论中我会说是对你最初问题的补充:
BitSet
可能是我们可以使用的最佳话虽这么说,我的建议是实现专用缓存解决方案,如果LRU是可接受的驱逐策略,则使用具有访问顺序的LinkedHashMap
,并在磁盘上具有永久存储对于BitSetS
。
伪代码:
class BitSetHolder {
class BitSetCache extends LinkedHashMap<Integer, Bitset> {
BitSetCache() {
LinkedHashMap(size, loadfactor, true); // access order ...
}
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > BitSetHolder.this.size; //size is knows in BitSetHolder
}
}
BitSet get(int i) { // get from cache if not from disk
if (bitSetCache.containsKey(i) {
return bitSetCache.get(i);
}
// if not in cache, put it in cache
BitSet bitSet = readFromDisk();
bitSetCache.put(i, bitSet);
return bitSet();
}
}
那样:
如果这是您的要求的选项,我可以开发一点。无论如何,这适用于其他驱逐策略,LRU是最简单的,因为它在LinkedHashMap
中是原生的。
答案 2 :(得分:0)
最佳解决方案在很大程度上取决于数据的使用模式和结构。
如果您的数据具有超出原始位blob的某种结构,那么您可以使用不同的数据结构做得更好。例如,可以使用DAG在空间和查找时间中非常有效地表示单词列表。
BitSet在内部表示为long [],这使得重构稍微困难一些。如果你从openjdk中获取源代码,你需要重写它,以便在内部使用迭代器,由文件或内存中的压缩blob支持。但是,您必须重写BitSet中的所有循环以使用迭代器,因此整个blob永远不必实例化。
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/BitSet.java