【炼气境】彻底搞懂hashcode

系列文章目录


文章目录

  • 系列文章目录
  • 一、Java中hashcode源码
  • 二、追踪JVM HotSpot中的实现
  • 三、总结


一、Java中hashcode源码

如图看到Object类中hashcode是一个native方法,什么是native方法?(native方法就是调用JVM中c/c++中的函数,Linux/Windows等操作系统的编码语言是c/c++,JVM虚拟机技术是将Java应用层开发与操作系统层做了隔离)
【炼气境】彻底搞懂hashcode_第1张图片

二、追踪JVM HotSpot中的实现

在此处说明一下,因为有安装的是jdk8,且虚拟机为HotSpot,因此这里是追踪HotSpot,如果你的虚拟机使用的是其他类型话,需要下载对应的虚拟机源码查看。
如何查看虚拟机类型?(见下图)
【炼气境】彻底搞懂hashcode_第2张图片
先说明下,一般我都是希望能引导大家学习怎么研究,不希望直接将结果给你,那样对新手或者初中级不友好,如果是高级或更牛的大牛,有兴趣的就看下结果接可以了。

OK,我们言归正传,下载JDK源码后,我们全局搜索下“hashcode”会看到如图代码位置
【炼气境】彻底搞懂hashcode_第3张图片
源码如下,然后发现又调用了ObjectSynchronizer::FastHashCode这个函数,找下它的位置如图。

JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  // as implemented in the classic virtual machine; return 0 if object is null
  return handle == nullptr ? 0 :
         checked_cast<jint>(ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)));
JVM_END

【炼气境】彻底搞懂hashcode_第4张图片
不要担心看不懂,编程语言都是大同小异的,这里看到"markWord",不知你有啥想法,如果没有想法,那你需要学习下Java Head对象头,搞懂它你再看这段代码就不会麻木了,同时你也会有更深层次的认识。此处后面我会放一个链接,专门写一篇Java Head的内容,如果希望我尽快出的话,请评论区留言!搞懂Java Head你就明白Java的GC对象年代怎么判断的了。

追踪至此结束,以下就是Object.hashCode()函数的具体实现算法,采用的是Marsaglia异或移位方案,特此说明下,在JDK之前版本中,使用的随机值算法。
【炼气境】彻底搞懂hashcode_第5张图片

// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stw_random}
// * CRC32 of {obj,stw_random} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
//   2654435761 = 2^32 * Phi (golden ratio)
//   HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stw_random ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stw_random) is appealing, but can result
//   in undesirable regularity in the hashCode values of adjacent objects
//   (objects allocated back-to-back, in particular).  This could potentially
//   result in hashtable collisions and reduced hashtable efficiency.
//   There are simple ways to "diffuse" the middle address bits over the
//   generated hashCode values:

static inline intptr_t get_next_hash(Thread* current, oop obj) {
  intptr_t value = 0;
  if (hashCode == 0) {
    // This form uses global Park-Miller 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 addr_bits = cast_from_oop<intptr_t>(obj) >> 3;
    value = addr_bits ^ (addr_bits >> 5) ^ GVars.stw_random;
  } else if (hashCode == 2) {
    value = 1;            // for sensitivity testing
  } else if (hashCode == 3) {
    value = ++GVars.hc_sequence;
  } 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 = current->_hashStateX;
    t ^= (t << 11);
    current->_hashStateX = current->_hashStateY;
    current->_hashStateY = current->_hashStateZ;
    current->_hashStateZ = current->_hashStateW;
    unsigned v = current->_hashStateW;
    v = (v ^ (v >> 19)) ^ (t ^ (t >> 8));
    current->_hashStateW = v;
    value = v;
  }

  value &= markWord::hash_mask;
  if (value == 0) value = 0xBAD;
  assert(value != markWord::no_hash, "invariant");
  return value;
}

三、总结

如果你看到了这里,相信屏幕前的你也是技术有追求的,有刨根问底精神的,因此我这里设置了一个问题,不妨将你的见解写在评论中。

问题:Object类中notify、wait等函数也是native方法,想想也能理解,因为需要控制线程映射到操作系统线程中对吧,但是像hashcode函数,只是通过算法计算得到一个整形数值,为什么要设计成native方法呢?岂不是要多余走Java调用c的调用链么,直接java层实现一下不行么?请在评论区说出你的理解。




                                                                                           ---- 永不磨灭的番号:AK



【炼气境】彻底搞懂hashcode_第6张图片

你可能感兴趣的:(Java架构修仙,java)