[英]What is the purpose of this code in IdentityHashMap.hash()?
/**
* Returns index for Object x.
*/
private static int hash(Object x, int length) {
int h = System.identityHashCode(x);
// Multiply by -127, and left-shift to use least bit as part of hash
return ((h << 1) - (h << 8)) & (length - 1);
}
来自: jdk/IdentityHashMap.java 在 jdk8-b120 · openjdk/jdk · GitHub
理论上System.identityHashCode()
返回的 hash 值已经是均匀分布的了,那为什么还要多一个移位运算而不是直接length - 1
的 AND 运算呢?
该实现似乎保证最低位为 0 以确保计算结果为偶数,因为该实现要求所有键都在偶数索引上,所有值都在奇数索引上。
h << 8
似乎混合了低位和高位来处理当 System.identityHashCode() 被实现为 memory 地址或递增值时的情况,目前尚不清楚为什么这里只移动 8 位而不是HashMap.hash()
也移动 16 位。
代码中的注释说:
hash table, as described for example in texts by Sedgewick and Knuth. The array alternates holding keys and values." “实施说明:这是一个简单的hash 表,如 Sedgewick 和 Knuth 的文本中的示例所述。数组交替保存键和值。”
事实上, hash
方法返回一个值,该值用作数组的直接索引。 例如:
public V get(Object key) {
Object k = maskNull(key);
Object[] tab = table;
int len = tab.length;
int i = hash(k, len);
while (true) {
Object item = tab[i];
if (item == k)
return (V) tab[i + 1];
if (item == null)
return null;
i = nextKeyIndex(i, len);
}
}
这意味着hash
需要返回偶数。 hash
中的计算确保索引是均匀的,而不会丢弃System.identityHashCode(x)
值的底部位。
为什么不扔掉最底层的部分呢?
好吧,答案在于System.identityHashCode
的实现方式。 实际上,有多种算法可以生成 hash,所使用的算法(在运行时)取决于一个模糊的 JVM 命令行选项。
一些算法(名义上)均匀分布在int
的范围内。 对于那些人,丢弃底部位就可以了。
其他算法不是这样的。 其中一种算法使用简单的全局计数器。 另一个使用对象的 memory 地址,删除了低 3 位。 如果选择这些算法,丢弃 LSB 会增加IdentityHashMap
中发生 hash 次冲突的概率。
有关IdentityHashcode
算法及其选择方式的更多信息,请参见https://shipilev.net/jvm/anatomy-quarks/26-identity-hash-code/ 。 请注意,JVM 行为的这一方面是未指定的,并且可能是特定于版本的。
我对这里发生的事情的预感是它旨在解决两个问题。
首先,这个 function 产生的槽索引必须是偶数。 (该实现将键存储在偶数表槽中,将值存储在奇数表槽中。)这意味着无论返回什么索引,其最后一位都必须为零。
其次,使用的标识 hash 代码(可能)基于 memory 地址,memory 地址的低位比高位“更随机”。 例如,如果我们分配一个对象列表,并且分配器将它们全部连续放置在 memory 中,那么它们的地址将具有相同的高位但低位不同。 (或者也许只有一个全局对象计数器在创建 object 时递增。在这种情况下,object 哈希的低位将同样比高位具有更广泛的分散。)
为了确保表格中的内容分散,我们因此希望将 hash 代码的低位与 hash 代码的“高”位“混合”。 减去h << 8
的效果是将标识 hash 代码的低位向上移动,翻转它们,然后将它们添加回 hash 代码,在加法运算时引起一堆“涟漪”。 我认为(?)这是一种有效的方法,可以将更高熵的低位注入高位,一旦表开始变得越来越大,就可以在槽阵列上提供更均匀的 hash。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.