`
xinglongbing
  • 浏览: 151122 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

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进行了定义:

 

// get a word with the n.th or the right-most or left-most n bits set
// (note: #define used only so that they can be used in enum constant definitions)
#define nth_bit(n)        (n >= BitsPerWord ? 0 : OneBit << (n))
#define right_n_bits(n)   (nth_bit(n) - 1)
#define left_n_bits(n)    (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))

// bit-operations using a mask m
inline void   set_bits    (intptr_t& x, intptr_t m) { x |= m; }
inline void clear_bits    (intptr_t& x, intptr_t m) { x &= ~m; }
inline intptr_t mask_bits      (intptr_t  x, intptr_t m) { return x & m; }
inline jlong    mask_long_bits (jlong     x, jlong    m) { return x & m; }
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

 

 

 \hotspot\src\share\vm\runtime\synchronizer.hpp中对hash value的产生的描述:// Returns the identity hash value for an oop
  // NOTE: It may cause monitor inflation
  static intptr_t identity_hash_value_for(Handle obj);
  static intptr_t FastHashCode (Thread * Self, oop obj) ;

 \hotspot\src\share\vm\runtime\synchronizer.cpp
中对上述两个函数: FastHashCode  identity_hash_value_for的具体实现:
intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
  if (UseBiasedLocking) {
    // NOTE: many places throughout the JVM do not expect a safepoint
    // to be taken here, in particular most operations on perm gen
    // objects. However, we only ever bias Java instances and all of
    // the call sites of identity_hash that might revoke biases have
    // been checked to make sure they can handle a safepoint. The
    // added check of the bias pattern is to avoid useless calls to
    // thread-local storage.
    if (obj->mark()->has_bias_pattern()) {
      // Box and unbox the raw reference just in case we cause a STW safepoint.
      Handle hobj (Self, obj) ;
      // Relaxing assertion for bug 6320749.
      assert (Universe::verify_in_progress() ||
              !SafepointSynchronize::is_at_safepoint(),
             "biases should not be seen by VM thread here");
      BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
      obj = hobj() ;
      assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
    }
  }

  // hashCode() is a heap mutator ...
  // Relaxing assertion for bug 6320749.
  assert (Universe::verify_in_progress() ||
          !SafepointSynchronize::is_at_safepoint(), "invariant") ;
  assert (Universe::verify_in_progress() ||
          Self->is_Java_thread() , "invariant") ;
  assert (Universe::verify_in_progress() ||
         ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;

  ObjectMonitor* monitor = NULL;
  markOop temp, test;
  intptr_t hash;
  markOop mark = ReadStableMark (obj);

  // object should remain ineligible for biased locking
  assert (!mark->has_bias_pattern(), "invariant") ;

  if (mark->is_neutral()) {
    hash = mark->hash();              // this is a normal header
    if (hash) {                       // if it has hash, just return it
      return hash;
    }
    hash = get_next_hash(Self, obj);  // allocate a new hash code
    temp = mark->copy_set_hash(hash); // merge the hash code into header
    // use (machine word version) atomic operation to install the hash
    test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
    if (test == mark) {
      return hash;
    }
    // If atomic operation failed, we must inflate the header
    // into heavy weight monitor. We could add more code here
    // for fast path, but it does not worth the complexity.
  } else if (mark->has_monitor()) {
    monitor = mark->monitor();
    temp = monitor->header();
    assert (temp->is_neutral(), "invariant") ;
    hash = temp->hash();
    if (hash) {
      return hash;
    }
    // Skip to the following code to reduce code size
  } else if (Self->is_lock_owned((address)mark->locker())) {
    temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
    assert (temp->is_neutral(), "invariant") ;
    hash = temp->hash();              // by current thread, check if the displaced
    if (hash) {                       // header contains hash code
      return hash;
    }
    // WARNING:
    //   The displaced header is strictly immutable.
    // It can NOT be changed in ANY cases. So we have
    // to inflate the header into heavyweight monitor
    // even the current thread owns the lock. The reason
    // is the BasicLock (stack slot) will be asynchronously
    // read by other threads during the inflate() function.
    // Any change to stack may not propagate to other threads
    // correctly.
  }

  // Inflate the monitor to set hash code
  monitor = ObjectSynchronizer::inflate(Self, obj);
  // Load displaced header and check it has hash code
  mark = monitor->header();
  assert (mark->is_neutral(), "invariant") ;
  hash = mark->hash();
  if (hash == 0) {
    hash = get_next_hash(Self, obj);
    temp = mark->copy_set_hash(hash); // merge hash code into header
    assert (temp->is_neutral(), "invariant") ;
    test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
    if (test != mark) {
      // The only update to the header in the monitor (outside GC)
      // is install the hash code. If someone add new usage of
      // displaced header, please update this code
      hash = test->hash();
      assert (test->is_neutral(), "invariant") ;
      assert (hash != 0, "Trivial unexpected object/monitor header usage.");
    }
  }
  // We finally get the hash
  return hash;
}

// Deprecated -- use FastHashCode() instead.

intptr_t ObjectSynchronizer::identity_hash_value_for(Handle obj) {
  return FastHashCode (Thread::current(), obj()) ;
}

 

 

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

 

// get a word with the n.th or the right-most or left-most n bits set
// (note: #define used only so that they can be used in enum constant definitions)
#define nth_bit(n)        (n >= BitsPerWord ? 0 : OneBit << (n))
#define right_n_bits(n)   (nth_bit(n) - 1)
#define left_n_bits(n)    (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))

// bit-operations using a mask m
inline void   set_bits    (intptr_t& x, intptr_t m) { x |= m; }
inline void clear_bits    (intptr_t& x, intptr_t m) { x &= ~m; }
inline intptr_t mask_bits      (intptr_t  x, intptr_t m) { return x & m; }
inline jlong    mask_long_bits (jlong     x, jlong    m) { return x & m; }
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.
 

 

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, //作为hash()函数第一个参数
         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作为hash()的第二个参数。
         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 };

 

 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提供大量的参考信息。

分享到:
评论
1 楼 冲杯茶喝 2012-11-15  
C++没学好,没大看懂,是不是返回的hash值就是返回的header中的那25位值?
这25位置是不是有对象的值算得?
请教

相关推荐

    Java Object类认识

    在Java编程语言中,`Object`类是所有类的根,每个自定义类如果没有明确指定父类,都默认继承自`Object`。因此,对`Object`类的理解是每个Java开发者的基本功。本文将深入探讨`Object`类,以及其核心方法`equals()`与...

    详解Java中Object 类的使用.rar

    在Java编程语言中,Object类是所有类的根类,无论是自定义的还是Java库中的类,它们都直接或间接地继承自Object类。这个压缩包文件"详解Java中Object 类的使用.rar"包含了对Java中Object类的深入探讨,通过阅读其中...

    Java的Object类讲解案例代码 equals()、hashCode()、finalize()、clone()、wait()

    这个源码资源是关于Java中的Object类的讲解案例代码。Object类是所有Java类的根类,它定义了一些常用的方法,例如equals()、hashCode()、toString()等。本案例代码将详细展示Object类的使用方法,并提供一些实际场景...

    Object类的hashCode的用法3---马克-to-win java视频

    Object类的hashCode的用法 马克-to-win java视频哈希码

    Java中equals,hashcode和==的区别

    "Java中equals、hashcode和==的区别" Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个...

    java中hashcode和equals的详解.pdf

    hashCode 方法是 Java 中 Object 类的一个方法,用于返回对象的哈希码值。这个方法的作用是将对象转换为一个整数值,以便于快速地比较和查找对象。在 Java 中,每个对象都有一个独特的哈希码值,这个值可以用来标识...

    java-object类

    `Object` 类是 Java 语言中最基础的类,位于 `java.lang` 包中。它是所有 Java 类的超类,即使程序员在定义一个新类时未明确指定该类继承自任何类,默认情况下,这个类也将继承自 `Object` 类。这意味着 `Object` 类...

    java中Hashcode的作用.docx

    在Java中,Hashcode的约定是由Java.lang.Object类中的hashCode方法所规定的。这个方法规定了Hashcode的三个基本原则: 1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则...

    Object类的hashCode的用法4---马克-to-win java视频

    Object类的hashCode的用法 马克-to-win java视频 哈希码

    java中object类实例分析

    在Java中,hashCode方法是Object类中的一个重要方法,它是所有Java类的父类。 toString方法是返回对象的字符串表示的方法。它可以将对象的属性转换为字符串,以便于程序内查看对象属性和调试代码。 在Java中,...

    Object类的hashCode的用法1---马克-to-win java视频

    Object类的hashCode的用法1---马克-to-win java视频哈希码

    JAVA之Object类所有方法

    在设计和实现类时,根据需要重写`equals()`、`hashCode()`和`toString()`方法,以满足特定的业务需求。同时,理解线程同步方法`wait()`、`notify()`和`notifyAll()`,能够帮助你构建并发安全的代码。

    Java Object实例代码

    Java Object 类是所有Java类的根,它定义了所有对象都具有的基本行为。在这个实例代码中,我们将深入探讨七个关键知识点,它们是Java Object的基础,对于理解和使用Java编程至关重要。 1. **对象**: 在Java中,...

    java中hashcode()和equals()的详解

    在Java编程语言中,`hashCode()`和`equals()`方法是对象身份验证的关键组成部分,它们主要用于对象的比较和哈希表(如HashMap、HashSet等)的操作。理解这两个方法的工作原理对于编写高效和可靠的代码至关重要。 ...

    如何正确实现Java中的HashCode共6页.pdf.z

    在Java编程语言中,`hashCode()`方法是每个对象都继承自`Object`类的一个关键功能。这个方法的主要目的是为对象生成一个整数哈希码,它通常用于优化数据结构,如哈希表(如`HashMap`和`HashSet`)。本教程“如何正确...

    Java Object 类高难度进阶版面试题集锦解析Java Object类高难度面试题及答案解析

    Java Object 类是所有Java类的根类,每个自定义的Java类都会无意识或有意识地继承Object类。Object类提供了几个核心的方法,这些方法在处理对象时非常关键,包括equals()、hashCode()、toString()、clone()、...

    JAVA_高级特性(hashCode,clone,比较器,Class反射,序列化)

    示例代码展示了如何在 `Person03` 类中实现 `clone` 方法: ```java public Object clone() throws CloneNotSupportedException { return super.clone(); } ``` 总结以上内容,Java 的这些高级特性为开发者提供了...

Global site tag (gtag.js) - Google Analytics