有人知道为低内存使用而优化的java.util.Map实现吗?

我看过通常的地方(apache commons,google)而找不到…

它应该是开源的。

几乎找到一个基于链表的。 用例是10’000的地图,不一定有很多值。它不需要按比例放大,因为当它变得太大时我可以转换它。

一些数字,大小使用一些计算的jvm值(8bytes / java.lang.Object,4bytes / ref)HashMap大约是100 + 32n字节,理论上最好的是12 + 20 * n。 < – 我想要那个,小n。

可以查看commons-collections Flat3Map ,它被优化为在3个字段中存储3个值并在4处溢出到另一个映射。

我没有看过实现,但可能值得考虑。 唯一的麻烦是,因为commons-collections与1.3兼容,所以没有通用的。

使用Map接口包装ArrayList。 ArrayList本身只使用几个字节。 每个节点都需要两个指针,一个用于键,一个用于值。 使用顺序搜索查找值。 只要只有很少的条目,性能就可以了[*]。 这将为您提供使用真实地图的余地,以便您拥有大量值的少数花瓶。

*:假设您的平均地图大小为10.今天的计算机每秒可以比较大约1亿个密钥,因此每次查找平均需要不到5微秒。

如果性能对于您的用例仍然太糟糕,您可以尝试按键对数组进行排序并使用二进制搜索。

好的,最后自己实现了。 我做了一个速度比较,发现与HashMap相比,它有4个条目的速度稍快,但5个或更多的速度更慢。 我用一长串的键进行了测试,我尝试给出类似的随机英语单词列表。

 import java.util.*; // PUBLIC DOMAIN public class SmallMap extends AbstractMap { private Entry entry = null; public void clear() { entry = null; } public boolean isEmpty() { return entry==null; } public int size() { int r = 0; for(Entry e = entry; e!=null; e = e.next) r++; return r; } public boolean containsKey(Object key) { for(Entry e = entry; e!=null; e = e.next){ if(e.key.equals(key)){ return true; } } return false; } public boolean containsValue(Object value) { for(Entry e = entry; e!=null; e = e.next){ if(e.value==null){ if(value==null) return true; }else if(e.value.equals(value)){ return true; } } return false; } public Object get(Object key) { for(Entry e = entry; e!=null; e = e.next){ if(e.key.equals(key)){ return e.value; } } return null; } public Object put(Object key, Object value) { for(Entry e = entry; e!=null; e = e.next){ if(e.key.equals(key)){ Object r = e.value; e.value = value; return r; } } entry = new Entry(key, value, entry); return null; } public Object remove(Object key) { if(entry!=null){ if(entry.key.equals(key)){ Object r = entry.value; entry = entry.next; return r; } for(Entry e = entry; e.next!=null; e = e.next){ if(key.equals(e.next.key)){ Object r = e.next.value; e.next = e.next.next; return r; } } } return null; } public Set entrySet() { return new EntrySet(); } class EntrySet extends AbstractSet{ public Iterator iterator() { return new Iterator(){ Entry last = null; Entry e = entry; public boolean hasNext() { return e!=null; } public Object next() { last = e; e = e.next; return last; } public void remove() { if(last == null) throw new IllegalStateException(); SmallMap.this.remove(last.key); } }; } public int size() { return SmallMap.this.size();} } static private class Entry implements java.util.Map.Entry { final Object key; Object value; Entry next; Entry(Object key, Object value, Entry next){ if(key==null) throw new NullPointerException(); this.key = key; this.value = value; this.next = next; } public Object getKey() { return key; } public Object getValue() { return value; } public Object setValue(Object value) { Object r = this.value; this.value = value; return r; } public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } } } 

简单地说,我建议根据同步或并发要求使用JDK的HashMap,Hashtable和ConcurrentHashMap之一。 如果您决定使用它们,在构造函数中适当地设置initialCapacity和loadFactor可能会有所帮助。

Google集合和apache commons集合提供了更多function:LRUMap,ReferenceMap,MultikeyMap等。 但我不认为只有小尺寸。

我认为LinkedHashMap使用链表,但我怀疑它是否针对低内存使用进行了优化。 通常,地图的整个点是加快从键到值的查找速度,这就解释了为什么你在常见的地方找不到你需要的东西。 编写自己的Map实现可能最简单,也许你甚至可以发布代码以防其他人需要相同的东西。

以隐藏地图使用的方式编写代码(无论如何你应该这样做,听起来你也是如此)。 在它重要的时候,因为你已经分析了代码并且可以看到内存确实是一个问题,找一个:-)

如果你现在知道存在问题,那么,抱歉我不知道。 然而,人们经常处理代码将会很慢/大量内存/等等的“想法”……并开始尝试预先优化它而不是使代码正确。

也就是说,如果你正在写一些你知道重要的东西,你应该随时测量。 例如,我正在研究解析类文件的代码,我做了一个小改动,然后看看它如何影响性能。 例如,我知道一个事实,即我所做的改变(3行)使我的程序慢了4倍……我花了一些时间在那一点上找不到更快的方法。

另外,如果“n”的值很小,你确定需要地图吗? 也许列表足够快? 您是否尝试调整现有Map以使其使用更少的内存?

也许这个答案有点晚,但看看Javolution项目。 它包含许多数据结构的实现,用于嵌入式和实时环境。 具体来说,有一个FastMap类可能只是你想要的。

如果您只存储String ,请查看http://code.google.com/p/flatmap

编辑哦对不起,我看到你正在寻找小而不大的地图,忘了我的建议。

这很大程度上取决于你将如何使用这些地图,你可以一次填充它们然后只进行查找(你需要那些查找速度快 )吗?

使用最少量内存的实现是将所有元素放在一个数组中并进行扫描以查找元素(但我想这不足以满足您的需求)…

如果你知道开头的所有元素,你可以尝试选择一个好的哈希方法而不会有太多的冲突。

或者,如果允许缓慢插入时间,也许你可以使用TreeMap …

我知道这是一个古老的问题,但也许有人可以添加更多的想法。

注意:以下内容仅对特定的用例子集有意义:

如果要求包括高度重叠的密钥集(在极端情况下是所有地图的相同密钥集),那么一个非常有效的解决方案可能是将地图关键字“外部化”并使地图仅包含值,arrays。

实现不应该在结构上依赖于重叠因子,但是当密钥重叠越多时,我的表现越好。 正如您所料。

我不能给出我的实现的确切细节,但重要的是有一个合适的机制来将键(存储在地图对象之外)转换为值数组中的索引,同时还允许值数组保持紧凑 ,即长度为5如果您的地图包含五个映射。

假设所有此类地图的键位于单独的地图中,映射到数字。 然后是一个关联数字和数组索引的方法。

很抱歉,如果这不够具体,但我认为这个想法同时很有趣和简单,并且可以用作开发内存效率Map的替代方向。

同样,它本身适用于高“密钥重叠”用例,但它本身就是通用的。 如果重叠太低,可能会遇到性能问题,具体取决于实现细节。