OpenHFT ChronicleMap 内存分配和限制

3
这篇文章很可能是OpenHFT的常见问题解答中的好候选者。
我正在尝试使用ChronicleMap来考虑一个想法,但有很多问题。我相信大多数正在研究该产品的初级程序员都有类似的疑虑。
你能解释一下这个API中内存是如何管理的吗?
ChronicleMap宣称拥有一些非常出色的离堆内存资源用于处理其数据,我想对此有一个清晰的认识。
让我们假设一个有500GB硬盘和4GB RAM的笔记本电脑程序员。在这种情况下,纯数学显示 - '交换'内存可用总资源量为504GB。让我们留一半给操作系统和其他程序,那么我们剩下250GB硬盘和2GB RAM。您能详细说明与可用资源相关的ChronicleMap可以分配的实际可用内存吗?
下一个相关的问题与ChronicleMap的实现有关。
我的理解是,每个ChronicleMap都会分配一个它所使用的内存块,并且当我们能够准确地预测通过的数据量时,就可以实现最佳性能/内存使用率。然而,这是一个动态的世界。
让我们设置一个(夸张但可能的)例子:
假设一个包含K(键)“城市”和它们的V(值)-“城市描述”的地图,并允许用户使用大量的描述长度限制。
第一个用户输入:K =“阿姆斯特丹”V =“自行车之城”,并使用此条目声明了地图 - 它为这个键值对设置了先例。
ChronicleMap<Integer, PostalCodeRange> cityPostalCodes = ChronicleMap
    .of(CharSequence.class, CharSequence.class)
    .averageKey("Amsterdam")
    .averageValue("City of bicycles")
    .entries(5_000)
    .createOrRecoverPersistedTo(citiesAndDescriptions);

现在,下一个用户写了一篇关于布拉格的文章。 他传递了:K =“Prague”V =“欧洲中心地带的100座塔城市…等等…数百万字…” 程序员预期最多有5,000个条目,但情况失控,出现了成千上万的条目。
ChronicleMap会自动为这种情况分配内存吗?如果是,是否有更好的方法声明ChronicleMaps以解决此动态解决方案?如果不是,您会推荐一种方法(最好提供代码示例)来处理这种情况吗?
这在持久性文件中如何工作?
ChronicleMaps会耗尽我的RAM和/或磁盘空间吗?避免这种情况的最佳实践是什么?
换句话说,请解释在低估值和高估值的情况下(键和/或值的长度和条目数),内存是如何管理的。
这些哪些适用于ChronicleMap?
1. 如果我分配了大块(.entries(1_000_000).averageValueSize(1_000_000),而实际使用情况为- Entries = 100,Average Value Size = 100。
会发生什么?
1.1 - 一切正常,但会有很多未使用的大块吗?
1.2 - 一切正常,未使用的内存可用于:
1.2.1- ChronicleMap 1.2.2- 使用ChronicleMap的给定线程
1.2.3- 给定进程
1.2.4- 给定JVM
1.2.5- 操作系统
1.3 - 请解释未使用的内存是否会发生其他情况
1.4 - 过大的声明对我的持久性文件有什么影响?
2. 与情况1相反-我分配了小块(.entries(10).averageValueSize(10)),而实际使用情况是100万条目和平均值大小为数千字节。
会发生什么?

嗨!请记住我们的社区由各种性别组成,如果你称呼他们为“绅士”,可能会让一些人感到被排斥。无论如何,我们更希望帖子中不包含任何问候语。谢谢! - halfer
1个回答

5
让我们来看一个配备500GB硬盘和4GB RAM的程序员。在这种情况下,纯数学表明 - '交换'内存的总资源可用量为504GB。让我们把一半留给操作系统和其他程序,我们还剩下250GB硬盘和2GB RAM。你能详细说明相对于可用资源,ChronicleMap实际可分配的可用内存数量吗?
在这种条件下,Chronicle Map将非常缓慢,每个操作都需要平均2次随机磁盘读写(总共4次随机磁盘操作)。传统的基于磁盘的数据库引擎,如RocksDBLevelDB,在数据库大小远大于内存时应该工作得更好。
现在程序员预计最多有5,000个条目,但是事实上数据量已经超出了他的控制,有成千上万个条目。
ChronicleMap会自动分配内存以适应这种情况吗?如果是,那么是否有更好的方法声明ChronicleMaps来解决这个动态问题?如果不是,你会推荐一种方法(最好附带代码示例)来处理这种情况吗?
Chronicle Map会分配内存,直到插入的实际条目数除以通过ChronicleMapBuilder.entries()配置的数量不高于配置的ChronicleMapBuilder.maxBloatFactor()。例如,如果您创建一个映射表如下:
ChronicleMap<Integer, PostalCodeRange> cityPostalCodes = ChronicleMap
    .of(CharSequence.class, CharSequence.class)
    .averageKey("Amsterdam")
    .averageValue("City of bicycles")
    .entries(5_000)
    .maxBloatFactor(5.0)
    .createOrRecoverPersistedTo(citiesAndDescriptions);

当大小约为25,000时,尝试插入新条目将开始抛出IllegalStateException。

然而,当实际大小远远超出配置大小时,Chronicle Map的工作速度会逐渐变慢,因此最大可能的maxBloatFactor()被人为地限制为1000。

目前的解决方案是通过entries()(和averageKey()、averageValue())正确配置未来的Chronicle Map大小。

需要事先配置合理的Chronicle Map大小的要求被认为是一个可用性问题。有一种方法可以解决这个问题,并且已经在项目路线图上了。


在估计键/值长度和条目数量时,如果低估了,内存管理的方式是什么?

键/值大小低估:每个条目在哈希查找区域中浪费大约8个字节*低估因子的空间。如果实际的平均条目大小(键+值)很小,例如50个字节,并且您将其配置为20个字节,则会浪费大约8*50/20=20字节,或40%。平均条目大小越大,浪费越小。
如果你只配置了键和值的平均大小,但没有直接配置actualChunkSize(),那么键/值大小会被高估。实际块大小将自动选择在平均条目大小(键+值)的1/8到1/4之间。实际块大小是Chronicle Map中的分配单位。因此,如果你将平均条目大小配置为约1000字节,则实际块大小将在125到250字节之间选择。如果实际平均条目大小仅为100字节,你将损失大量空间。如果过度估计很小,预期的空间损失仅限于数据大小的约20%。因此,如果你担心可能高估平均键/值大小,请明确配置actualChunkSize()条目数量低估: 如上所述。没有特定的空间浪费,但是Chronicle Map的工作速度会随着低估程度的加剧而变慢。

条目数量高估: 在哈希查找区域中浪费了内存,每个条目浪费 ~8字节 * 高估因子。请参见上面的键/值大小低估部分,了解它可能是好是坏,具体取决于实际平均条目数据大小。


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