【问题标题】:How is the Object class implemented (methods like hashCode and internal fields)?Object 类是如何实现的(hashCode 和内部字段等方法)?
【发布时间】:2012-11-26 11:53:56
【问题描述】:

我很好奇 Object 类是如何实现的。例如

  1. 方法 hashCode() 或 wait()
  2. 如何表示内部状态。 例如,内在锁或用于存储调用对象的 wait() 线程的数据结构。

为了找出这些,我下载了一个OpenJDK的源代码并开始挖掘。首先,我遇到了\openjdksrc\jdk\src\share\native\java\lang\Object.c文件,其中包括:

static JNINativeMethod methods[] = {
    {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
    {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
    {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
    {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
    {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
{
    if (this == NULL) {
        JNU_ThrowNullPointerException(env, NULL);
        return 0;
    } else {
        return (*env)->GetObjectClass(env, this);
    }
}

据我了解,methods[] 数组定义了 Object 方法的本机实现之间的映射。例如,Object 的 hashCode() 映射到 JVM_IHashCode 函数。 JVM_IHashCode 在 \openjdksrc\hotspot\src\share\vm\prims\jvm.cpp 中实现。这是我的第一个问题。 为什么这已经是 VM 本身的一部分(它已经在 \openjdksrc\hotspot\src\share\vm 中定义了)? 但是让我们转到 JVM_IHashCode 的代码:

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

为什么如果 object 为 null,我们会在此处返回 0? 我想应该抛出 NPE。否则,从 \openjdksrc\hotspot\src\share\vm\runtime\synchronizer.cpp 调用 FastHashCode 并最终在某个时间点调用 get_next_hash 来计算实际值。 计算后问题是存储在哪里?

    intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {

...CUT...

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

...CUT...

      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.
      } 
...CUT...
      return hash;
    }

所以 oop 类/结构 (?) 有一个 markOop 类/结构 (?),其中存储了哈希值。 Funilly 我找不到这些类/结构。我只能找到:

class oopDesc {
  friend class VMStructs;
 private:
  volatile markOop  _mark;
...CUT...

在 \openjdksrc\hotspot\src\share\vm\oops\oop.hpp 这似乎在私人领域有markOop。 但是,在其余代码中引用的“oop”到底是什么?而在哪里可以找到markOop的定义?我找到了对应的:

class markOopDesc: public oopDesc 
...CUT...

在 \openjdksrc\hotspot\src\share\vm\oops\markOop.hpp 但它只是充满了枚举并且找不到可以存储哈希值的字段。 如果有人能至少回答我的部分问题,我将不胜感激。谢谢!

【问题讨论】:

标签: java object jvm


【解决方案1】:

Java 对象的哈希码在计算后存储在对象头中。

http://www.javamex.com/tutorials/memory/object_memory_usage.shtml

http://hunmr.blogspot.com/2012/08/java-performance-tunning.html

来自热点/src/share/vm/oops/markOop.hpp

// The markOop describes the header of an object.
//
// 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, big endian layout below):
//
//  32 bits:
//  --------
//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
//             size:32 ------------------------------------------>| (CMS free block)
//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
//

【讨论】:

  • 供参考:“OOP”这里的意思是“普通对象指针”。
  • 谢谢!我的脑海里又冒出几个问题。我在网站上读到您指的是对象标头占用 8 个字节。这里看起来是 16 个字节(每行 4 个字节 * 4 行)。我也对某些字段的大小感到好奇。为什么哈希只有 25 位?为什么锁是2位的?我认为只有 1 位用于锁定就足够了。还有哪些字段:age、epoch 和 promo_bits?
  • @Janek,好问题。我认为“正常”和“有偏见”的对象状态是相互排斥的。也适用于“免费 CMD”和“推广 CMS”。年龄用于实现基于代的内存管理。时代?promo_bits?我不知道。所有答案都在源代码中。 :)
  • @whunmr 你说哈希码存储在“对象头文件”中是什么意思?头文件是 C/C++ 中的静态文件?还是为每个 Class 生成一个新的头文件,其中一个值是您上面描述的 32 位数据?
  • @mk1 for "object header" 我的意思是java对象实例占用的内存的头部/开始部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-20
  • 2011-03-09
  • 2012-11-16
  • 2013-09-01
相关资源
最近更新 更多