【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?

之前看其他文章说,hashcode是根据对象的内存地址生成的。但为了满足自己的好奇心,同时验证这个结论是否是真实的,我半个月前深究了一下。今天突然想起来这回事了,把结论记录一下。


结论

目前hashcode的方式有以下六种算法:

  • HashCodeMode==0:由操作系统生成的一个随机数
  • HashCodeMode==1:基于对象内存地址计算哈希值
  • HashCodeMode==2:定值1 ,(始终返回固定的标识哈希码值1,用于测试)。
  • HashCodeMode==3:从零开始递增地计算哈希码值。
  • HashCodeMode==4: 对象的内存地址转为int类型。
  • HashCodeMode>=5:默认算法,它使用Marsaglia的异或移位方案生成的随机数(https://en.wikipedia.org/wiki/Xorshift)。

默认情况下:

  1. JDK8、JDK9下默认是HashCodeMode = 5,即默认并不是通过对象内存地址计算得来的,与对象的内存地址无关
  2. JDK6、JDK7下默认是HashCodeMode = 0

特殊情况:

也可以根据-XX:hashCode=2来调整默认的算法。

证明

JDK6:
【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_第1张图片
JDK7
【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_第2张图片
JDK8
【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_第3张图片

JDK9
【有趣的小细节】在Java中native方法hashcode()默认是如何生成哈希码的?_第4张图片

代码证明


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

你可能感兴趣的:(Java基础,哈希算法,java,算法,对象内存地址)