繁体   English   中英

Java memory 优化了 [Key:Long, Value:Long] 存储非常大(500M)的并发读取访问

[英]Java memory optimized [Key:Long, Value:Long] store of very large size (500M) for concurrent read-access

我有一个用例,我需要存储大小约为的键值对。 大小为 8 GB 的单个 VM 中有 5 亿个条目。 Key 和 Value 的类型为 Long。 键从 1、2、3 开始自动递增,依此类推..

只有一次我在程序开始时将这个 Map[KV] 结构构建为独占操作,一旦构建,仅用于查找,在此结构中不执行更新或删除。

我已经用 java.util.hashMap 试过这个,但正如预期的那样,它消耗了大量的 memory 并且程序给出了 OOM:堆使用超过错误。

我需要一些有助于减少 memory 占用空间的指导,但访问性能会有所下降。

  1. 可以在此处尝试的其他替代方案(来自 java 集合或其他库)是什么。
  2. 出于比较目的,通过此 Map 获得 memory 足迹的推荐方法是什么。

只需使用long[]long[][]

5 亿个升序键小于 2^31。 如果您的 go 超过 2^31,请使用long[][] ,其中第一个维度很小,第二个维度很大。

(当键类型为 integer 时,如果键空间稀疏,则只需要复杂的“映射”数据结构。)

一维数组中的空间浪费是微不足道的。 每个Java数组节点有12字节header,节点大小向上取整为8字节的倍数。 因此,一个 5 亿个条目long[]将需要接近 5 亿 x 8 字节 == 40 亿字节,这无关紧要。

但是,JVM 通常不能分配占用整个可用堆空间的单个 object。 如果虚拟地址空间非常宝贵,建议使用二维数组; 例如new long[4][125_000_000] 这会使查找稍微复杂一些,但这样做很可能会减少memory 的占用空间。


如果您事先不知道预期的键数,您可以使用 arrays 和ArrayList对象的组合来做同样的事情。 但是ArrayList的问题是,如果您不设置(准确的)容量,则 memory 的利用率可能会不理想。 如果您通过附加来填充ArrayList ,则对append的瞬时 memory 需求可能是列表当前空间使用量的 3 倍。

在您的情况下,没有理由使用Map

如果您只有一个起始索引并且进一步的索引只是恒定增量,只需使用List

List<Long> data=new ArrayList<>(510_000_000);//capacity should ideally not be reached, if it is reached, the array behind the ArrayList needs to be reallocated, the allocated memory would be doubled by that

data.add(1337L);//inserting, how often you want

long value=data.get(1-1);//1...your index that starts with 1, -1...because your index starts with 1, you should subtract one from the index.

如果您甚至不添加更多元素并且从一开始就知道大小,那么数组会更好:

long[] data=long[510_000_000];//capacity should surely not be reached, you will need to create a new array and copy all data if it is higher
int currentIndex=0;

data[currentIndex++]=1337L//inserting, as often as it is smaller than the size

long value=data[1-1];//1...your index that starts with 1, -1...because your index starts with 1, you should subtract one from the index.

请注意,您应该在插入之前检查索引( currentIndex ),使其小于数组长度。

迭代时,使用currentIndex+1作为长度而不是.length

创建一个具有您需要的大小的数组,并在您需要访问它时使用arr[i-1]-1因为您的 indizes 以1而不是零开头)。

如果你“只是”有 5 亿个条目,你将不会达到 integer 限制,一个简单的数组就可以了。

如果您需要更多条目并且有足够的内存,请使用 arrays 数组。

使用这么大的阵列的 memory 占用空间是数据的 memory 占用空间等等。

但是,如果您不知道尺寸,则应使用可能需要的更高长度/容量。 如果您使用ArrayList ,则只要达到容量,memory 的占用空间就会增加一倍(暂时增加三倍),因为它需要分配更大的阵列。

Map需要每个条目的 object 和所有那些 object 的列表数组,这将大大增加 ZCD69B4957F06CD8298D7BF 占用空间。 memory 占用空间的增加(使用HashMap )甚至比使用ÀrrayList更糟糕,因为即使Map未完全填满,也会重新分配底层数组。

但如果您需要存储这么多数据,请考虑将其保存到 HDD/SSD。 在大多数情况下,这会更好。 您可以使用RandomAccessFile在任何点访问 HDD/SSD 上的数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM