之前看其他文章说,hashcode
是根据对象的内存地址生成的。但为了满足自己的好奇心,同时验证这个结论是否是真实的,我半个月前深究了一下。今天突然想起来这回事了,把结论记录一下。
结论
目前hashcode的方式有以下六种算法:
-
HashCodeMode==0
:由操作系统生成的一个随机数。 -
HashCodeMode==1
:基于对象内存地址计算哈希值 -
HashCodeMode==2
:定值1
,(始终返回固定的标识哈希码值1,用于测试)。 -
HashCodeMode==3
:从零开始递增地计算哈希码值。 -
HashCodeMode==4
: 对象的内存地址转为int类型。 -
HashCodeMode>=5
:默认算法,它使用Marsaglia的异或移位方案生成的随机数(https://en.wikipedia.org/wiki/Xorshift
)。
默认情况下:
- JDK8、JDK9下默认是
HashCodeMode = 5
,即默认并不是通过对象内存地址计算得来的,与对象的内存地址无关 - JDK6、JDK7下默认是
HashCodeMode = 0
特殊情况:
也可以根据-XX:hashCode=2
来调整默认的算法。
证明
JDK6:JDK7JDK8
JDK9
代码证明
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
// This form uses an unguarded global Park-Miller RNG,
// so it's possible for two threads to race and generate the same RNG.
// On MP system we'll have lots of RW access to a global, so the
// mechanism induces lots of coherency traffic.
value = os::random() ;
} else
if (hashCode == 1) {
// This variation has the property of being stable (idempotent)
// between STW operations. This can be useful in some of the 1-0
// synchronization schemes.
intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else
if (hashCode == 2) {
value = 1 ; // for sensitivity testing
} else
if (hashCode == 3) {
value = ++GVars.hcSequence ;
} else
if (hashCode == 4) {
value = cast_from_oop<intptr_t>(obj) ;
} else {
// Marsaglia's xor-shift scheme with thread-specific state
// This is probably the best overall implementation -- we'll
// likely make this the default in future releases.
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
Self->_hashStateX = Self->_hashStateY ;
Self->_hashStateY = Self->_hashStateZ ;
Self->_hashStateZ = Self->_hashStateW ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}
value &= markOopDesc::hash_mask;
if (value == 0) value = 0xBAD ;
assert (value != markOopDesc::no_hash, "invariant") ;
TEVENT (hashCode: GENERATE) ;
return value;
}
参考
https://hg.openjdk.org/jdk6/jdk6/hotspot/file/5cec449cc409/src/share/vm/runtime/globals.hpp#l1128
https://srvaroa.github.io/jvm/java/openjdk/biased-locking/2017/01/30/hashCode.html
https://hg.openjdk.org/jdk9/jdk9/hotspot/file/fc7e94cb7485/src/share/vm/runtime/globals.hpp#l1198
https://hg.openjdk.org/jdk9/jdk9/hotspot/file/fc7e94cb7485/src/share/vm/runtime/globals.hpp#l1198
https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/globals.hpp