轻量级 Java Map 实现(内存开销小)

3

我正在编写一些Java代码,旨在为一个围绕着拥有数十亿条目的数据库的项目构建一个小型框架。我希望保持高级别,并且从数据库中检索的数据应该很容易用于统计推断。我决定在这个项目中使用Map接口。

核心概念是将属性(“数据库中的列”)映射到值(“单元格”),以处理单个数据集(我指的是数据库中的列)时使代码可读:我使用枚举对象(命名为“Attribute”)表示属性类型,这意味着映射<Attribute,String>,因为数据元素都是字符串(也不是很大,最多40个字符左右)。总共有15列,所以有15个枚举,而地图将只有这么多条目或更少。

因此,看起来我将有很多Map对象在某些时候浮动,但是相对较小的有效载荷(15-)。我的目标是不要由于实现内存开销而使内存爆炸,与实际有效载荷相比。(拉伸目标:使用相同的CPU使用量;])

我之前并不真正熟悉Java Collections的所有不同实现,当今天问题出现时,我查看了迄今为止我最喜欢的'HashMap',并且对宣布的内存开销感到不满意。我相信,除了标准实现之外,还有许多未随Java一起发货的实现。搜索我的情况没有带来太多结果,所以我问你:

您是否知道适用于我的用例(低条目计数,低价值大小,可枚举键等)的Map实现?

我希望我已经清楚地阐述了我的用例,并且渴望听取您的意见=)非常感谢!


拉伸答案目标,绝对是可选的,只有在您有时间和知识的情况下才适用:

  • 处理属性(字符串)向量和推理数据的矩阵(计数/概率)的集合实现(矩阵:在这里我真的一无所知,迄今为止没有使用Java进行过严肃的数学工作)
  • 用于统计推断的数学库,参见上文

我不认为这直接回答了你的问题,但是看一下Google Guava集合框架https://code.google.com/p/guava-libraries/可能值得你花时间,因为它们有一些非常好的Map实现。 - David
请查看memcached的相关内容,网址为http://www.javaworld.com/javaworld/jw-04-2012/120418-memcached-for-java-enterprise-performance.html。 - fmodos
1
你想一直将数十亿条记录保存在内存中吗?我认为你实际上不想使用任何Java Map实现。你很可能需要一个由某种存储系统支持的映射,该系统将值存储在当前VM的内存之外。这很可能不涉及使用Java Map。 - Deadron
3个回答

7

如果你的键是枚举类型,建议使用EnumMap,这是最佳的映射实现,无论是性能还是内存使用方面都很优秀。

这个映射实现的技巧在于它不会存储键,它只需要一个包含值的单一数组(类似于值的ArrayList)。如果有一些键没有映射到值,那么只有一点点额外开销,但大多数情况下这并不是一个问题,因为枚举通常不具有太多的实例。

HashMap相比,你可以免费获得可预测的迭代顺序。


1
哇,这不是完美的解决方案吗 =)我怎么没有找到它。谢谢! - simlei

5

如果你想存储大量数据,最终你也需要访问/修改这些数据。市面上有许多高性能的库。

看一下:

当你发现瓶颈时,可以切换到使用更低级别的API(更有效率)

如果再多找一点,你会发现更多选择: What is the most efficient Java Collections library?

编辑:如果你的字符串不是唯一的,你可以使用String.intern()来节省大量内存:Is it good practice to use java.lang.String.intern()?


谢谢提供这些库,我会研究一下。上面也提到了Fastutil,看起来非常不错=) - simlei

3
你可以使用一个简单的map实现来节省一些内存,该实现使用两个数组列表(键和值)。对于较大的映射,这意味着插入和查找速度会变得更慢,因为您必须扫描整个列表。但是,对于小型映射,这种方式实际上更快,因为您不必计算任何哈希码,只需查看少量条目即可。
如果您需要实现,请查看我的jsonj项目中的SimpleMap:https://github.com/jillesvangurp/jsonj/blob/master/src/main/java/com/github/jsonj/SimpleMap.java

自己实现 - 我喜欢这个想法。说实话,这个想法之前没有出现在我的脑海中,但我猜这可能是对性能控制最多的选项。 - simlei
这个肯定使用了更少的内存。如果你想要更主流的东西,Trove或Guava可能有一些不错的实现。顺便说一句,使用对象序列化可以让你很好地了解你节省了多少内存。只需将其序列化为bytearrayoutputstream并计算字节数即可。 - Jilles van Gurp
Fastutil(http://fastutil.di.unimi.it/)实现了这个概念,包括特定于原始类型的版本,以避免装箱/拆箱。查找适当的TypeA2TypeBArrayMap。 - Ian Roberts
Fastutil 确实看起来很有前途。感谢你的指引! - simlei
感谢大家的回答;我将使用EnumMap,因为它似乎是为我的用例编写的类,并且不需要链接到外部库。 - simlei

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接