【问题标题】:Java hashmap with single byte[] array for all keysJava hashmap,所有键的单字节 [] 数组
【发布时间】:2017-01-25 01:08:28
【问题描述】:

我有一个相当大的数据集,包含 2.3GB 的数据,分布在 1.6 亿字节 [] 数组中,平均数据长度为 15 字节。每个 byte[] 键的值只是一个 int,因此将近一半的 hashmap(超过 6GB)的内存使用量由每个字节数组的 16 字节开销组成

开销 = 8 字节标头 + 4 字节长度由 VM 四舍五入到 16 字节。

所以我的开销是 2.5GB。

是否有人知道将其(可变长度)字节 [] 键存储在一个大字节数组中的 hashmap 实现,因此不会有任何开销(除了 1 字节长度字段)?

我宁愿不使用内存数据库,因为与我正在使用的普通 Trove TObjectIntHashMap 相比,它们通常具有性能开销,而且我更重视 CPU 周期而不是内存使用量。

提前致谢

【问题讨论】:

  • 数组没有实现 equals() 或 hashCode(),你的 Trove hashmap 是否为你提供了这些?
  • 你为什么使用byte[]作为你的hashmap的key
  • 你使用的是什么 JVM?我的印象是,如果byte[] 的长度是奇数,开销只会是 12 个字节,因为只是整个结构被四舍五入到 8 的倍数。
  • 我用 >new TObjectIntCustomHashMap(new HashingStrategy() 覆盖 equals() 和 hashCode() 我正在使用 byte[] 因为这就是我的数据! , byte[] 大小并不总是奇数

标签: java arrays hashmap


【解决方案1】:

由于如今大多数个人计算机都有 16GB,而服务器通常有 32 - 128 GB 或更多,因此存在一定程度的簿记开销是否存在真正的问题?

如果我们考虑替代方案:将字节数据连接到一个大数组中——我们应该考虑单个值的外观,以引用更大数组的切片。

通常你会从以下开始:

public class ByteSlice {
    protected byte[] array;
    protected int offset;
    protected int len;
}

但是,这是 8 个字节 + 指针的大小(可能只有 4 个字节?)+ JVM 对象头(在 64 位 JVM 上为 12 个字节)。所以可能总共 24 个字节。

如果我们尝试使这个单一用途和极简主义,我们仍然需要 4 个字节作为偏移量。

public class DedicatedByteSlice {
    protected int offset;
    protected byte len;

    protected static byte[] getArray() {/*somebody else knows about the array*/}
}

这仍然是 5 个字节(可能填充为 8)+ JVM 对象头。可能仍然总共 20 个字节。

似乎使用偏移量和长度进行解引用以及使用对象来跟踪它的成本大大低于直接存储小数组的成本。

另一种理论上的可能性——解构 Map Key 使其不是对象

可以设想解构“长度和偏移”数据,使其不再存在于对象中。然后它作为一组标量参数传递,例如(长度,偏移量),并且 - 在哈希映射实现中 - 将通过单独组件的数组存储(例如,而不是单个 Object[] keyArray)。

但是我认为任何库都不太可能为您的(非常特殊的)用例提供现有的 hashmap 实现。

如果您谈论的是 ,那可能毫无意义,因为 Java 不提供多个返回或方法 OUT 参数;如果没有将解构的数据“装箱”回对象,这使得通信变得不切实际。由于您在这里专门询问 Map Keys,并且这些作为参数传递但不需要返回,因此理论上可以考虑这种方法。

[扩展] 即使考虑到这一点,它也变得很棘手——对于您的用例,地图 API 可能必须在填充与查找方面变得不对称,因为填充必须按 (offset, len) 来定义键;而实际查找可能仍然是通过具体的 byte[] 数组。

OTOH:即使是相当旧的笔记本电脑现在也有 16GB。而且您编写此代码的时间(维护时间为 4-10 倍)应该远远超过额外 RAM 的小成本。

【讨论】:

  • 是的,我在想一个简单的 get(int offset, byte len) 问题然后是哈希函数,你如何找到将 byte[] 键转换为单个大的偏移量的偏移量所有键的字节 [] 数组,而无需将数组划分为固定长度的“桶”,这些“桶”必须与最大键一样大,这将浪费大量空间,因为平均键大小将远小于最大键大小。我有 32GB 内存,但我在处理过程中将其余的内存用于其他数据(需要解释很多),因此我需要节省内存使用量。
猜你喜欢
  • 1970-01-01
  • 2014-03-15
  • 2012-08-07
  • 2015-11-03
  • 1970-01-01
  • 2019-07-13
  • 2021-04-14
  • 2017-05-04
  • 1970-01-01
相关资源
最近更新 更多