诸如无处不在的HashMap
类的标准Java Map最终受到可用RAM的限制。 阅读本文并了解如何创建几乎无限大小甚至超过目标计算机的RAM大小的Java Map。
内置的Map实现,例如HashMap
和ConcurrentHashMap
,只要它们相对较小,就可以正常工作。 在所有情况下,它们都受可用堆的限制,因此最终受可用RAM大小的限制。 ChronicleMap
可以将其内容存储在文件中,从而规避了此限制,为TB级的映射打开了空间,如有关CronicleMap
系列文章的第二篇文章所示。
在我之前的第一篇文章中了解有关CronicleMap
基础知识的更多信息。
文件映射
通过在ChronicleMap构建器上调用createPersistedTo()
方法来进行文件映射,如下所示:
private static Map<Long, Point> createFileMapped() {try {return ChronicleMap.of(Long.class, Point.class).averageValueSize(8).valueMarshaller(PointSerializer.getInstance()).entries(10_000_000).createPersistedTo(new File("my-map"));} catch (IOException ioe) {throw new RuntimeException(ioe);}
}
这将创建一个Map,将其内容布局在名为“ my-map”的内存映射文件中,而不是直接内存中。 以下示例说明了如何创建1000万个Point
对象并将其全部存储在文件映射图中:
final Map<Long, Point> m3 = LongStream.range(0, 10_000_000).boxed().collect(toMap(Function.identity(),FillMaps::pointFrom,(u, v) -> {throw new IllegalStateException();},FillMaps::createFileMapped));
以下命令显示了新创建的文件:
Pers-MacBook-Pro:target pemi$ ls -lart my-map
-rw-r--r-- 1 pemi staff 330305536 Jul 10 16:56 my-map
可以看出,该文件约为33 MB,因此每个条目平均占用33个字节。
坚持不懈
当JVM终止时,映射文件仍然存在,从而可以轻松地拾取先前创建的包含其内容的映射。 这非常类似于基本的超快数据库。 这是我们从现有文件开始的方法:
return ChronicleMap.of(Long.class, Point.class).averageValueSize(8).valueMarshaller(PointSerializer.getInstance()).entries(10_000_000).createOrRecoverPersistedTo(new File("my-map"));
该Map
将直接可用,包括以前的内容。
Java Map超出RAM限制
内存映射文件的一个有趣方面是,它们可以超过堆和RAM的限制。 文件映射逻辑将确保当前使用的部件按需加载到RAM中。 映射逻辑还将在物理内存中保留已访问映射内存的最新部分,以提高性能。 这发生在幕后,不需要由应用程序本身进行管理。
我的台式计算机是只有16GB内存的较旧的MacBook Pro(是的,我知道那很糟)。 不过,我可以分配一个Map
其中包含10亿个条目,它们可能占用33 * 1,000,000,000 = 33 GB内存(我们从上面记得,每个条目平均占用33个字节)。 代码如下:
return ChronicleMap.of(Long.class, Point.class).averageValueSize(8).valueMarshaller(PointSerializer.getInstance()).entries(1_000_000_000).createPersistedTo(new File("huge-map"));
即使我尝试用2倍于我的RAM大小创建Java Map,代码也可以完美运行,并得到以下文件:
Pers-MacBook-Pro:target pemi$ ls -lart | grep huge-map
-rw-r--r-- 1 pemi staff 34573651968 Jul 10 18:52 huge-map
不用说,您应该确保要映射的文件位于具有较高随机访问性能的文件系统上。 例如,位于本地SSD上的文件系统。
摘要
ChronicleMap可以映射到外部文件
JVM退出时保留映射的文件
新应用程序可以选择现有的映射文件 ChronicleMap可以容纳的数据多于RAM 映射文件最好放在具有较高随机访问性能的文件系统上
翻译自: https://www.javacodegeeks.com/2019/08/java-chroniclemap-super-ram-maps.html