Java中Object类hashCode的实现

在ZangXT的帮助下,跟踪Object类的native方法hashCode方法从jvm源码中得到了下面的一些内容,供参考。

Object中hashCode方法是一个本地方法:public native int hashCode();

对于Java HotSpot VM,首先介绍一个概念就是对象的header,每个对象都会有一个header,header由两个机器字表示(8个字节对于32位架构,16个字节对于64位架构)。header的第一个字中有7位用做同步及垃圾收集,另外25位存储对象的hash码。header的第二个字存储指向对应Class对象的指针(Class对象用来保存类的元数据信息及方法表)。

这里要追踪的就是存放在对象header中的那25位hash码。

在JVM的\hotspot\src\share\vm\oops\markOop.hpp文件中有对markOop类的说明:
The markOop describes the header of an object.即markOop是用来描述对象的header的。

其中包含有产生hash值的函数,如下:

  // hash operations
  intptr_t hash() const {
    return mask_bits(value() >> hash_shift, hash_mask);
  }

以下是markOop中包含的类markOopDesc,其中包含了描述对象的一些数据结构:当然也包含了产生hash值所必须的一些信息下面用红色作为标记:

class markOopDesc: public oopDesc {
 private:
  // Conversion
  uintptr_t value() const { return (uintptr_t) this; }

 public:
  // Constants
  enum { age_bits                 = 4,
         lock_bits                = 2,
         biased_lock_bits         = 1,
         max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
         hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
         epoch_bits               = 2
  };

  // The biased locking code currently requires that the age bits be
  // contiguous to the lock bits. Class data sharing would prefer the
  // hash bits to be lower down to provide more random hash codes for
  // shared read-only symbolOop objects, because these objects' mark
  // words are set to their own address with marked_value in the lock
  // bit, and using lower bits would make their identity hash values
  // more random. However, the performance decision was made in favor
  // of the biased locking code.

  enum { lock_shift               = 0,
         biased_lock_shift        = lock_bits,
         age_shift                = lock_bits + biased_lock_bits,
         hash_shift               = lock_bits + biased_lock_bits + age_bits,
         epoch_shift              = hash_shift
  };

  enum { lock_mask                = right_n_bits(lock_bits),
         lock_mask_in_place       = lock_mask << lock_shift,
         biased_lock_mask         = right_n_bits(lock_bits + biased_lock_bits),
         biased_lock_mask_in_place= biased_lock_mask << lock_shift,
         biased_lock_bit_in_place = 1 << biased_lock_shift,
         age_mask                 = right_n_bits(age_bits),
         age_mask_in_place        = age_mask << age_shift,
         epoch_mask               = right_n_bits(epoch_bits),
         epoch_mask_in_place      = epoch_mask << epoch_shift
#ifndef _WIN64
         ,hash_mask               = right_n_bits(hash_bits),
         hash_mask_in_place       = (address_word)hash_mask << hash_shift
#endif
  };

  // Alignment of JavaThread pointers encoded in object header required by biased locking
  enum { biased_lock_alignment    = 2 << (epoch_shift + epoch_bits)
  };

#ifdef _WIN64
    // These values are too big for Win64
    const static uintptr_t hash_mask = right_n_bits(hash_bits);
    const static uintptr_t hash_mask_in_place  =
                            (address_word)hash_mask << hash_shift;
#endif

  enum { locked_value             = 0,
         unlocked_value           = 1,
         monitor_value            = 2,
         marked_value             = 3,
         biased_lock_pattern      = 5
  };

  enum { no_hash                  = 0 };  // no hash value assigned

  enum { no_hash_in_place         = (address_word)no_hash << hash_shift,
         no_lock_in_place         = unlocked_value
  };

  enum { max_age                  = age_mask };

  enum { max_bias_epoch           = epoch_mask };

 

我们知道hash值的产生最终依赖于另一个函数mask_bits

\hotspot\src\share\vm\utilities\globalDefinitions.hpp中对mask_bits进行了定义:

 

Java代码   收藏代码
  1. // get a word with the n.th or the right-most or left-most n bits set  
  2. // (note: #define used only so that they can be used in enum constant definitions)  
  3. #define nth_bit(n)        (n >= BitsPerWord ? 0 : OneBit << (n))  
  4. <span style="color: #ff0000;">#define right_n_bits(n)   (nth_bit(n) - 1)</span>  
  5. #define left_n_bits(n)    (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))  
  6.   
  7. // bit-operations using a mask m  
  8. inline void   set_bits    (intptr_t& x, intptr_t m) { x |= m; }  
  9. inline void clear_bits    (intptr_t& x, intptr_t m) { x &= ~m; }  
  10. <span style="color: #ff0000;">inline intptr_t mask_bits      (intptr_t  x, intptr_t m) { return x & m; }</span>  
  11. inline jlong    mask_long_bits (jlong     x, jlong    m) { return x & m; }  
  12. inline bool mask_bits_are_true (intptr_t flags, intptr_t mask) { return (flags & mask) == mask; }  

 

由此已经找到了产生hash值的根源,根据定义看出该hash值跟多个对象头部中的变量有关。

 

 

 

 

/hotspot/src/share/vm/prims/jvm.cpp中的定义:

// java.lang.Object ///
JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_IHashCode");
  // as implemented in the classic virtual machine; return 0 if object is NULL
  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
JVM_END

 

 

Java代码   收藏代码
  1.  \hotspot\src\share\vm\runtime\synchronizer.hpp中对hash value的产生的描述:// Returns the identity hash value for an oop  
  2.   // NOTE: It may cause monitor inflation  
  3.   static intptr_t identity_hash_value_for(Handle obj);  
  4.   static intptr_t FastHashCode (Thread * Self, oop obj) ;  
  5.   
  6.  \hotspot\src\share\vm\runtime\synchronizer.cpp  
  7. 中对上述两个函数: FastHashCode  identity_hash_value_for的具体实现:  
  8. intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {  
  9.   if (UseBiasedLocking) {  
  10.     // NOTE: many places throughout the JVM do not expect a safepoint  
  11.     // to be taken here, in particular most operations on perm gen  
  12.     // objects. However, we only ever bias Java instances and all of  
  13.     // the call sites of identity_hash that might revoke biases have  
  14.     // been checked to make sure they can handle a safepoint. The  
  15.     // added check of the bias pattern is to avoid useless calls to  
  16.     // thread-local storage.  
  17.     if (obj->mark()->has_bias_pattern()) {  
  18.       // Box and unbox the raw reference just in case we cause a STW safepoint.  
  19.       Handle hobj (Self, obj) ;  
  20.       // Relaxing assertion for bug 6320749.  
  21.       assert (Universe::verify_in_progress() ||  
  22.               !SafepointSynchronize::is_at_safepoint(),  
  23.              "biases should not be seen by VM thread here");  
  24.       BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());  
  25.       obj = hobj() ;  
  26.       assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");  
  27.     }  
  28.   }  
  29.   
  30.   // hashCode() is a heap mutator ...  
  31.   // Relaxing assertion for bug 6320749.  
  32.   assert (Universe::verify_in_progress() ||  
  33.           !SafepointSynchronize::is_at_safepoint(), "invariant") ;  
  34.   assert (Universe::verify_in_progress() ||  
  35.           Self->is_Java_thread() , "invariant") ;  
  36.   assert (Universe::verify_in_progress() ||  
  37.          ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;  
  38.   
  39.   ObjectMonitor* monitor = NULL;  
  40.   markOop temp, test;  
  41.   intptr_t hash;  
  42.   markOop mark = ReadStableMark (obj);  
  43.   
  44.   // object should remain ineligible for biased locking  
  45.   assert (!mark->has_bias_pattern(), "invariant") ;  
  46.   
  47.   if (mark->is_neutral()) {  
  48.     hash = mark->hash();              // this is a normal header  
  49.     if (hash) {                       // if it has hash, just return it  
  50.       return hash;  
  51.     }  
  52.     hash = get_next_hash(Self, obj);  // allocate a new hash code  
  53.     temp = mark->copy_set_hash(hash); // merge the hash code into header  
  54.     // use (machine word version) atomic operation to install the hash  
  55.     test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);  
  56.     if (test == mark) {  
  57.       return hash;  
  58.     }  
  59.     // If atomic operation failed, we must inflate the header  
  60.     // into heavy weight monitor. We could add more code here  
  61.     // for fast path, but it does not worth the complexity.  
  62.   } else if (mark->has_monitor()) {  
  63.     monitor = mark->monitor();  
  64.     temp = monitor->header();  
  65.     assert (temp->is_neutral(), "invariant") ;  
  66.     hash = temp->hash();  
  67.     if (hash) {  
  68.       return hash;  
  69.     }  
  70.     // Skip to the following code to reduce code size  
  71.   } else if (Self->is_lock_owned((address)mark->locker())) {  
  72.     temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned  
  73.     assert (temp->is_neutral(), "invariant") ;  
  74.     hash = temp->hash();              // by current thread, check if the displaced  
  75.     if (hash) {                       // header contains hash code  
  76.       return hash;  
  77.     }  
  78.     // WARNING:  
  79.     //   The displaced header is strictly immutable.  
  80.     // It can NOT be changed in ANY cases. So we have  
  81.     // to inflate the header into heavyweight monitor  
  82.     // even the current thread owns the lock. The reason  
  83.     // is the BasicLock (stack slot) will be asynchronously  
  84.     // read by other threads during the inflate() function.  
  85.     // Any change to stack may not propagate to other threads  
  86.     // correctly.  
  87.   }  
  88.   
  89.   // Inflate the monitor to set hash code  
  90.   monitor = ObjectSynchronizer::inflate(Self, obj);  
  91.   // Load displaced header and check it has hash code  
  92.   mark = monitor->header();  
  93.   assert (mark->is_neutral(), "invariant") ;  
  94.   hash = mark->hash();  
  95.   if (hash == 0) {  
  96.     hash = get_next_hash(Self, obj);  
  97.     temp = mark->copy_set_hash(hash); // merge hash code into header  
  98.     assert (temp->is_neutral(), "invariant") ;  
  99.     test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);  
  100.     if (test != mark) {  
  101.       // The only update to the header in the monitor (outside GC)  
  102.       // is install the hash code. If someone add new usage of  
  103.       // displaced header, please update this code  
  104.       hash = test->hash();  
  105.       assert (test->is_neutral(), "invariant") ;  
  106.       assert (hash != 0"Trivial unexpected object/monitor header usage.");  
  107.     }  
  108.   }  
  109.   // We finally get the hash  
  110.   return hash;  
  111. }  
  112.   
  113. // Deprecated -- use FastHashCode() instead.  
  114.   
  115. intptr_t ObjectSynchronizer::identity_hash_value_for(Handle obj) {  
  116.   return FastHashCode (Thread::current(), obj()) ;  
  117. }  

 

 

\hotspot\src\share\vm\utilities\globalDefinitions.hpp中对mask_bits进行了定义:

 

Java代码   收藏代码
  1. // get a word with the n.th or the right-most or left-most n bits set  
  2. // (note: #define used only so that they can be used in enum constant definitions)  
  3. #define nth_bit(n)        (n >= BitsPerWord ? 0 : OneBit << (n))  
  4. #define right_n_bits(n)   (nth_bit(n) - 1)  
  5. #define left_n_bits(n)    (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))  
  6.   
  7. // bit-operations using a mask m  
  8. inline void   set_bits    (intptr_t& x, intptr_t m) { x |= m; }  
  9. inline void clear_bits    (intptr_t& x, intptr_t m) { x &= ~m; }  
  10. inline intptr_t mask_bits      (intptr_t  x, intptr_t m) { return x & m; }  
  11. inline jlong    mask_long_bits (jlong     x, jlong    m) { return x & m; }  
  12. inline bool mask_bits_are_true (intptr_t flags, intptr_t mask) { return (flags & mask) == mask; }  

 

 


\hotspot\src\share\vm\oops\markOop.hpp文件中对markOop类的说明:

The markOop describes the header of an object.
其中包含有:

  // hash operations
  intptr_t hash() const {
    return mask_bits(value() >> hash_shift, hash_mask);
  }

可见hash函数又是通过mask_bits函数调用返回hash值的,通过返回的值的类型:intptr可以看出返回的应该是对象的地址。不过mask_bits函数最终没有找到;。
Note that the mark is not a real oop but just a word.
// It is placed in the oop hierarchy for historical reasons.
//
// Bit-format of an object header (most significant first):
//
//
//  unused:0/25 hash:25/31 age:4 biased_lock:1 lock:2 = 32/64 bits
上面红色标记的文字说明了markOop是用来描述一个对象的头部,其中32位架构中有25位用来存储hash值,其他的7位用于同步和垃圾回收。
//  - hash contains the identity hash value: largest value is
//    31 bits, see os::random().  Also, 64-bit vm's require
//    a hash value no bigger than 32 bits because they will not
//    properly generate a mask larger than that: see library_call.cpp
//    and c1_CodePatterns_sparc.cpp.
//
//  - the biased lock pattern is used to bias a lock toward a given
//    thread. When this pattern is set in the low three bits, the lock
//    is either biased toward a given thread or "anonymously" biased,
//    indicating that it is possible for it to be biased. When the
//    lock is biased toward a given thread, locking and unlocking can
//    be performed by that thread without using atomic operations.
//    When a lock's bias is revoked, it reverts back to the normal
//    locking scheme described below.
//
//    Note that we are overloading the meaning of the "unlocked" state
//    of the header. Because we steal a bit from the age we can
//    guarantee that the bias pattern will never be seen for a truly
//    unlocked object.
//
//    Note also that the biased state contains the age bits normally
//    contained in the object header. Large increases in scavenge
//    times were seen when these bits were absent and an arbitrary age
//    assigned to all biased objects, because they tended to consume a
//    significant fraction of the eden semispaces and were not
//    promoted promptly, causing an increase in the amount of copying
//    performed. The runtime system aligns all JavaThread* pointers to
//    a very large value (currently 128 bytes) to make room for the
//    age bits when biased locking is enabled.
//
//    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
//    [0           | epoch | age | 1 | 01]       lock is anonymously biased
//
//  - the two lock bits are used to describe three states: locked/unlocked and monitor.
//
//    [ptr             | 00]  locked             ptr points to real header on stack
//    [header      | 0 | 01]  unlocked           regular object header
//    [ptr             | 10]  monitor            inflated lock (header is wapped out)
//    [ptr             | 11]  marked             used by markSweep to mark an object
//                                               not valid at any other time
//
//    We assume that stack/thread pointers have the lowest two bits cleared.
 

 

Java代码   收藏代码
  1. class markOopDesc: public oopDesc {  
  2.  private:  
  3.   // Conversion  
  4.   <span style="color: #800000;">uintptr_t value() const { return (uintptr_t) this; }</span>  
  5.   
  6.  public:  
  7.   // Constants  
  8.   enum { age_bits                 = 4,  
  9.          lock_bits                = 2,  
  10.          biased_lock_bits         = 1,  
  11.          max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,  
  12.          hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,  
  13.          epoch_bits               = 2  
  14.   };  
  15.   
  16.   // The biased locking code currently requires that the age bits be  
  17.   // contiguous to the lock bits. Class data sharing would prefer the  
  18.   // hash bits to be lower down to provide more random hash codes for  
  19.   // shared read-only symbolOop objects, because these objects' mark  
  20.   // words are set to their own address with marked_value in the lock  
  21.   // bit, and using lower bits would make their identity hash values  
  22.   // more random. However, the performance decision was made in favor  
  23.   // of the biased locking code.  
  24.   
  25.   enum { lock_shift               = 0,  
  26.          biased_lock_shift        = lock_bits,  
  27.          age_shift                = lock_bits + biased_lock_bits,  
  28.          hash_shift               = lock_bits + biased_lock_bits + age_bits, //作为hash()函数第一个参数  
  29.          epoch_shift              = hash_shift  
  30.   };  
  31.   
  32.   enum { lock_mask                = right_n_bits(lock_bits),  
  33.          lock_mask_in_place       = lock_mask << lock_shift,  
  34.          biased_lock_mask         = right_n_bits(lock_bits + biased_lock_bits),  
  35.          biased_lock_mask_in_place= biased_lock_mask << lock_shift,  
  36.          biased_lock_bit_in_place = 1 << biased_lock_shift,  
  37.          age_mask                 = right_n_bits(age_bits),  
  38.          age_mask_in_place        = age_mask << age_shift,  
  39.          epoch_mask               = right_n_bits(epoch_bits),  
  40.          epoch_mask_in_place      = epoch_mask << epoch_shift  
  41. #ifndef _WIN64  
  42.          ,hash_mask               = right_n_bits(hash_bits), //hash_mask作为hash()的第二个参数。  
  43.          hash_mask_in_place       = (address_word)hash_mask << hash_shift  
  44. #endif  
  45.   };  
  46.   
  47.   // Alignment of JavaThread pointers encoded in object header required by biased locking  
  48.   enum { biased_lock_alignment    = 2 << (epoch_shift + epoch_bits)  
  49.   };  
  50.   
  51. #ifdef _WIN64  
  52.     // These values are too big for Win64  
  53.     const static uintptr_t hash_mask = right_n_bits(hash_bits);  
  54.     const static uintptr_t hash_mask_in_place  =  
  55.                             (address_word)hash_mask << hash_shift;  
  56. #endif  
  57.   
  58.   enum { locked_value             = 0,  
  59.          unlocked_value           = 1,  
  60.          monitor_value            = 2,  
  61.          marked_value             = 3,  
  62.          biased_lock_pattern      = 5  
  63.   };  
  64.   
  65.   enum { no_hash                  = 0 };  // no hash value assigned  
  66.   
  67.   enum { no_hash_in_place         = (address_word)no_hash << hash_shift,  
  68.          no_lock_in_place         = unlocked_value  
  69.   };  
  70.   
  71.   enum { max_age                  = age_mask };  
  72.   
  73.   enum { max_bias_epoch           = epoch_mask };  

 

 markOopDesc继承自oopDesc

oopDesc在\hotspot\src\share\vm\oops\oop.hpp中的定义:

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
  union _metadata {
    wideKlassOop    _klass;
    narrowOop       _compressed_klass;
  } _metadata;
 

 

 http://xieyj.iteye.com/?page=2&show_full=true

 

\hotspot\src\share\vm

\hotspot\src\share\vm\oops

hotspot\src\share\vm\runtime

下面有很多关键的信息,有时间再去看看。

十分感谢ZangXT提供大量的参考信息。


原文:http://xinglongbing.iteye.com/blog/343484

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值