日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java:ChronicleMap第1部分,精简版

發(fā)布時(shí)間:2023/12/3 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java:ChronicleMap第1部分,精简版 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

用數(shù)百萬個(gè)對(duì)象填充HashMap會(huì)很快導(dǎo)致諸如內(nèi)存使用效率低下,性能低下和垃圾回收等問題。 了解如何使用堆外CronicleMap ,其中可以包含數(shù)十億個(gè)對(duì)象,而對(duì)堆的影響很小或沒有。

當(dāng)我們要使用中小型數(shù)據(jù)集時(shí),內(nèi)置的Map實(shí)現(xiàn)(例如HashMap和ConcurrentHashMap是出色的工具。 但是,隨著數(shù)據(jù)量的增長(zhǎng),這些
Map的實(shí)現(xiàn)正在惡化,并開始表現(xiàn)出如約開放sourceed的系列文章的第一篇文章中一些令人不快的缺點(diǎn)CronicleMap 。

堆分配

在下面的示例中,我們將使用Point對(duì)象。 Point是一個(gè)POJO,具有公共默認(rèn)構(gòu)造函數(shù)以及X和Y屬性(int)的getter和setter。 以下代碼段將一百萬個(gè)Point對(duì)象添加到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; }

我們可以很容易地看到堆上分配的對(duì)象數(shù)量以及這些對(duì)象消耗多少堆內(nèi)存:

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 )

對(duì)于每個(gè)Map條目,都需要在堆上創(chuàng)建Long , HashMap$Node和Point對(duì)象。 還有許多創(chuàng)建了HashMap$Node對(duì)象的數(shù)組。 這些對(duì)象和數(shù)組總共消耗了88,515,056字節(jié)的堆內(nèi)存。 因此,每個(gè)條目平均消耗88.5個(gè)字節(jié)。

注意:額外的2429 HashMap$Node對(duì)象來自Java內(nèi)部使用的其他HashMap對(duì)象。

堆外分配

與此相反, CronicleMap使用很少的堆內(nèi)存,運(yùn)行以下代碼時(shí)可以看到:

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分配對(duì)象
CronicleMap條目,因此也沒有堆內(nèi)存。

CronicleMap不會(huì)分配堆內(nèi)存,而是分配堆外內(nèi)存,而不是分配堆內(nèi)存。 假設(shè)我們使用標(biāo)志-XX:NativeMemoryTracking=summary啟動(dòng)JVM,則可以通過發(fā)出以下命令來檢索正在使用的堆外內(nèi)存量:

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

顯然,我們的一百萬個(gè)對(duì)象使用略多于30 MB的堆外RAM放置在堆外內(nèi)存中。 這意味著,
CronicleMap使用的CronicleMap平均需要30個(gè)字節(jié)。

這比需要88.5字節(jié)的HashMap內(nèi)存有效得多。 實(shí)際上,我們節(jié)省了66%的RAM內(nèi)存和近100%的堆內(nèi)存。 后者很重要,因?yàn)镴ava垃圾收集器只能看到堆上的對(duì)象。

注意,我們必須在創(chuàng)建時(shí)決定CronicleMap最多可以容納多少個(gè)條目。 相比于
HashMap可以隨著我們添加新的關(guān)聯(lián)而動(dòng)態(tài)增長(zhǎng)。 我們還必須提供一個(gè)序列化程序 (即PointSerializer.getInstance() ),本文稍后將對(duì)此進(jìn)行詳細(xì)討論。

垃圾收集

許多垃圾回收(GC)算法在與堆中存在的對(duì)象的平方成比例的時(shí)間內(nèi)完成。 因此,例如,如果我們將堆上的對(duì)象數(shù)量加倍,則可以預(yù)期GC將花費(fèi)四倍的時(shí)間才能完成。

另一方面,如果我們創(chuàng)建的對(duì)象增加了64倍,則預(yù)期的預(yù)期GC時(shí)間將增加1,024倍。 這有效地阻止了我們創(chuàng)造出巨大的
HashMap對(duì)象。

使用ChronicleMap我們可以放置新的關(guān)聯(lián),而無需擔(dān)心垃圾收集時(shí)間。

序列化器

堆內(nèi)存與堆外內(nèi)存之間的介體通常稱為
序列化器 。 ChronicleMap帶有許多針對(duì)大多數(shù)內(nèi)置Java類型(例如Integer , Long , String等)的預(yù)配置序列化器。

在上面的示例中,我們使用了一個(gè)自定義的序列化程序,該序列化程序用于在堆內(nèi)存與堆外內(nèi)存之間來回轉(zhuǎn)換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; } }

上面的序列化器實(shí)現(xiàn)為無狀態(tài)單例,并且write()和read()方法中的實(shí)際序列化非常簡(jiǎn)單。 唯一棘手的部分是,我們需要在
如果“ using”變量未引用實(shí)例化/重用的對(duì)象,則為read()方法。

如何安裝?

當(dāng)我們想在項(xiàng)目中使用ChronicleMap時(shí),只需在pom.xml文件中添加以下Maven依賴項(xiàng),就可以訪問該庫。

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

如果您使用的是另一種構(gòu)建工具(例如Gradle),則可以通過單擊此鏈接來了解如何依賴ChronicleMap 。

短篇小說

以下是ChronicleMap的一些屬性:

堆外存儲(chǔ)數(shù)據(jù)
幾乎總是比HashMap更高的內(nèi)存效率
實(shí)現(xiàn)ConcurrentMap 不影響垃圾收集時(shí)間 有時(shí)需要一個(gè)序列化器 具有固定的最大條目大小 可以容納數(shù)十億個(gè)協(xié)會(huì) 是免費(fèi)和開源的

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

總結(jié)

以上是生活随笔為你收集整理的Java:ChronicleMap第1部分,精简版的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。