用数百万个对象填充HashMap会很快导致诸如内存使用效率低下,性能低下和垃圾回收等问题。 了解如何使用堆外CronicleMap ,其中可以包含数十亿个对象,而对堆的影响很小或没有。

当我们要使用中小型数据集时,内置的Map实现(例如HashMapConcurrentHashMap是出色的工具。 但是,随着数据量的增长,这些
Map的实现正在恶化,并开始表现出如约开放sourceed的系列文章的第一篇文章中一些令人不快的缺点CronicleMap

堆分配

在下面的示例中,我们将使用Point对象。 Point是一个POJO,具有公共默认构造函数以及X和Y属性(int)的getter和setter。 以下代码段将一百万个Point对象添加到HashMap

 final Map<Long, Point> m = LongStream.range( 0 , 1_000_000) .boxed() .collect( toMap( Function.identity(), FillMaps::pointFrom, (u,v) -> { throw new IllegalStateException(); }, IllegalStateException(); }, HashMap:: new ) ); // Conveniency method that creates a Point from // a long by applying modulo prime number operations private static Point pointFrom( long seed) { final Point point = new Point(); point.setX(( int ) seed % 4517 ); point.setY(( int ) seed % 5011 ); return point; } 

我们可以很容易地看到堆上分配的对象数量以及这些对象消耗多少堆内存:

 Pers-MacBook-Pro:chronicle-test pemi$ jmap -histo 34366 | head | head num    #instances        #bytes class name (module)  ------------------------------------------------------- 1 : 1002429 32077728 java.util.HashMap$Node (java.base @10 ) 2 : 1000128 24003072 java.lang.Long (java.base @10 ) 3 : 1000000 24000000 com.speedment.chronicle.test.map.Point 4 : 454 8434256 [Ljava.util.HashMap$Node; (java.base [Ljava.util.HashMap$Node; (java.base @10 ) 5 : 3427 870104 [B (java.base @10 ) 6 : 185 746312 [I (java.base @10 ) 7 : 839 102696 java.lang.Class (java.base @10 ) 8 : 1164 89088 [Ljava.lang.Object; (java.base [Ljava.lang.Object; (java.base @10 ) 

对于每个Map条目,都需要在堆上创建LongHashMap$NodePoint对象。 还有许多创建了HashMap$Node对象的数组。 这些对象和数组总共消耗了88,515,056字节的堆内存。 因此,每个条目平均消耗88.5个字节。

注意:额外的2429 HashMap$Node对象来自Java内部使用的其他HashMap对象。

堆外分配

与此相反, CronicleMap使用很少的堆内存,运行以下代码时可以看到:

 final Map<Long, Point> m2 = LongStream.range( 0 , 1_000_000) .boxed() .collect( toMap( Function.identity(), FillMaps::pointFrom, (u,v) -> { throw new IllegalStateException(); }, IllegalStateException(); }, () -> ChronicleMap .of(Long. class , Point. class ) .averageValueSize( 8 ) .valueMarshaller(PointSerializer.getInstance()) .entries(1_000_000) .create() ) ); 
 Pers-MacBook-Pro:chronicle-test pemi$ jmap -histo 34413 | head | head num    #instances        #bytes class name (module)  ------------------------------------------------------- 1 : 6537 1017768 [B (java.base @10 ) 2 : 448 563936 [I (java.base @10 ) 3 : 1899 227480 java.lang.Class (java.base @10 ) 4 : 6294 151056 java.lang.String (java.base @10 ) 5 : 2456 145992 [Ljava.lang.Object; (java.base [Ljava.lang.Object; (java.base @10 ) 6 : 3351 107232 java.util.concurrent.ConcurrentHashMap$Node (java.base @10 ) 7 : 2537 81184 java.util.HashMap$Node (java.base @10 ) 8 : 512 49360 [Ljava.util.HashMap$Node; (java.base [Ljava.util.HashMap$Node; (java.base @10 ) 

可以看出,没有为Java分配对象
CronicleMap条目,因此也没有堆内存。

CronicleMap不会分配堆内存,而是分配堆外内存,而不是分配堆内存。 假设我们使用标志-XX:NativeMemoryTracking=summary启动JVM,则可以通过发出以下命令来检索正在使用的堆外内存量:

 Pers-MacBook-Pro:chronicle-test pemi$ jcmd 34413 VM.native_memory | grep Internal VM.native_memory | grep Internal  -                 Internal (reserved=30229KB, committed=30229KB) 

显然,我们的一百万个对象使用略多于30 MB的堆外RAM放置在堆外内存中。 这意味着,
CronicleMap使用的CronicleMap平均需要30个字节。

这比需要88.5字节的HashMap内存有效得多。 实际上,我们节省了66%的RAM内存和近100%的堆内存。 后者很重要,因为Java垃圾收集器只能看到堆上的对象。

注意,我们必须在创建时决定CronicleMap最多可以容纳多少个条目。 相比于
HashMap可以随着我们添加新的关联而动态增长。 我们还必须提供一个序列化程序 (即PointSerializer.getInstance() ),本文稍后将对此进行详细讨论。

垃圾收集

许多垃圾回收(GC)算法在与堆中存在的对象的平方成比例的时间内完成。 因此,例如,如果我们将堆上的对象数量加倍,则可以预期GC将花费四倍的时间才能完成。

另一方面,如果我们创建的对象增加了64倍,则预期的预期GC时间将增加1,024倍。 这有效地阻止了我们创造出巨大的
HashMap对象。

使用ChronicleMap我们可以放置新的关联,而无需担心垃圾收集时间。

序列化器

堆内存与堆外内存之间的介体通常称为
序列化器ChronicleMap带有许多针对大多数内置Java类型(例如IntegerLongString等)的预配置序列化器。

在上面的示例中,我们使用了一个自定义的序列化程序,该序列化程序用于在堆内存与堆外内存之间来回转换Point 。 序列化器类如下所示:

 public final class PointSerializer implements SizedReader<Point>, SizedWriter<Point> { private static PointSerializer INSTANCE = new PointSerializer(); public static PointSerializer getInstance() { return INSTANCE; } INSTANCE; } private PointSerializer() {} @Override public long size( @NotNull Point toWrite) { return Integer.BYTES * 2 ; } @Override public void write(Bytes out, long size, @NotNull Point point) { out.writeInt(point.getX()); out.writeInt(point.getY()); } @NotNull @Override public Point read(Bytes in, long size, Point using) { @Nullable Point using) { if (using == null ) { using = new Point(); } using.setX(in.readInt()); using.setY(in.readInt()); return using; }  } 

上面的序列化器实现为无状态单例,并且write()read()方法中的实际序列化非常简单。 唯一棘手的部分是,我们需要在
如果“ using”变量未引用实例化/重用的对象,则为read()方法。

如何安装?

当我们想在项目中使用ChronicleMap时,只需在pom.xml文件中添加以下Maven依赖项,就可以访问该库。

 < dependency > < groupId >net.openhft</ groupId > < artifactId >chronicle-map</ artifactId > < version >3.17.3</ version >  </ dependency > 

如果您使用的是另一种构建工具(例如Gradle),则可以通过单击此链接来了解如何依赖ChronicleMap

短篇小说

以下是ChronicleMap的一些属性:

堆外存储数据
几乎总是比HashMap更高的内存效率
实现ConcurrentMap 不影响垃圾收集时间 有时需要一个序列化器 具有固定的最大条目大小 可以容纳数十亿个协会 是免费和开源的

翻译自: https://www.javacodegeeks.com/2019/08/java-chroniclemap-part-1-go-off-heap.html

Java:ChronicleMap第1部分,精简版相关推荐

  1. java下标运算符_《Java从小白到大牛精简版》之第6章 运算符(下)

    <Java从小白到大牛>纸质版已经上架了!! 6.4 位运算符 位运算是以二进位(bit)为单位进行运算的,操作数和结果都是整型数据.位运算符有如下几个运算符:&.|.^.~.&g ...

  2. Java 编程规范 -- 易错精简版

    Part 1 – 易错点 --  edit by liudeyu,If you have any adivice or suggestion, please participate in the di ...

  3. java 精简版jre_超级精简版的jre

    [实例简介] 超级精简版的jre,超级精简版的jre,超级精简版的jre,超级精简版的jre [实例截图] [核心代码] 超级精简版的jre └── jre ├── bin │   ├── clien ...

  4. 微信java精简版低内存_微信精简版低内存apk-微信精简版2019下载v7.0.6 安卓版-腾牛安卓网...

    微信精简版,去除繁杂的功能,保留最核心的微信通讯.公众号等功能,去除升级永保低内存运行,适合各类高旧手机,使用微信再也不会面临卡顿,内存占用太大等问题了. 版本特性: 1.去除升级 2.去除游戏等各种 ...

  5. 精简版开发工具使用手记(图解)

    以下记录一些精简版开发工具的使用情况.C#的精简开发工具SharpDevelop,VC++ 6.0绿色版,Java的开发工具JCreator,.... 一 SharpDevelop 5.0 压缩包大小 ...

  6. NOSQL系列-Redis精简版安装与Ruby测试

    简介:Redis是一个NOSQL数据库,它是一款key-values存储型数据库,也叫"memcached改进版",它不同与memcached最大特点是它由内存+硬盘来存储数据的, ...

  7. Log4j快速使用精简版

    Log4j快速使用精简版 1.导入log4j-1.2.17.jar包 2.在src根目录下创建log4j.properties文件 log4j.rootLogger=INFO, CONSOLE, FI ...

  8. MiniDao-PE精简版

    https://github.com/zhangdaiscott/minidao-pe MiniDao-PE精简版 MiniDao-PE 简介及特征 MiniDao-PE 是一种持久化解决方案,类似m ...

  9. java8精简的jre,精简版jre,只有9M多哦!

    [实例简介] 精简版jre,适用于桌面应用程序,打包发布. [实例截图] [核心代码] 9b7eb008-4687-4222-97dc-f18c123aa26d └── jre ├── bin │   ...

  10. 雨林木风 Ghost XP SP2 精简版 Y2.0

    雨林木风 Ghost XP SP2 精简版 Y2.0 [b] [/b] [b] [b][/b] 雨林木风 Ghost XP SP2 精简版 Y2.0 MD5:9c97185b2d344d2369d99 ...

最新文章

  1. LeetCode简单题之生成每种字符都是奇数个的字符串
  2. GEMM性能提升200倍,AutoKernel算子优化工具正式开源
  3. XShell上无法通过rz上传空文件,通过新建文件来实现
  4. python ccbox_python--easygui
  5. python中怎么比较两个列表的大小_在Python中比较两个大小不同的列表
  6. java学习(159):两个线程共同完成1到100计算
  7. Laravel源码解析之事件系统
  8. sqlite3常用技巧
  9. 最短路径之Dijkstra算法和Floyd-Warshall算法
  10. java对接金蝶接口
  11. 柠檬班python自动化百度云_带三开头的名字女孩名字大全
  12. 生物特征识别技术的安全性分析
  13. Microsoft SQL Server Reporting Services 初探
  14. 使用Kaiju无组装计算宏基因组数据物种注释相对丰度
  15. 破解神器Hashcat使用简介
  16. 5W2H工作法,使工作更有条理,生活更好梳理
  17. CSS3视窗单位vw、vh、vmin、vmax说明
  18. PDF文件如何转JPG图片?三种方法教你快速转换
  19. 算法设计与分析: 6-8 圆排列问题
  20. mysql事务的四个特点和实现原理

热门文章

  1. jzoj1266,P1879-[USACO06NOV]玉米田Corn Fields【状态压缩,dp】
  2. 2021“MINIEYE杯”中国大学生算法设计超级联赛(5)Random Walk 2(推式子+矩阵逆+矩阵乘)
  3. Educational Codeforces Round 48
  4. CVPR19 基于图卷积网络的多标签图像识别模型 论文笔记
  5. 关于 NIO 你不得不知道的一些“地雷”
  6. 如何quot;优雅quot;地终止一个线程?
  7. 一张图搞清楚Java异常机制
  8. 阿里面试回来,想和 Java 程序员谈一谈
  9. 第三章用sql语句操作数据
  10. JS向对象中添加和删除属性