【有趣的小细节】在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:
在这里插入图片描述
JDK7
在这里插入图片描述
JDK8
在这里插入图片描述

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

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Honyelchak

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值