從 JDK 原始碼角度看 Object

seaboat發表於2017-06-27

Java的Object是所有其他類的父類,從繼承的層次來看它就是最頂層根,所以它也是唯一一個沒有父類的類。它包含了物件常用的一些方法,比如getClasshashCodeequalsclonetoStringnotifywait等常用方法。所以其他類繼承了Object後就可以不用重複實現這些方法。這些方法大多數是native方法,下面具體分析。

主要的程式碼如下:

public class Object {

  private static native void registerNatives();

  static {
    registerNatives();
  }

  public final native Class<?> getClass();

  public native int hashCode();

  public boolean equals(Object obj) {
    return (this == obj);
  }

  protected native Object clone() throws CloneNotSupportedException;

  public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
  }

  public final native void notify();

  public final native void notifyAll();

  public final native void wait(long timeout) throws InterruptedException;

  public final void wait(long timeout, int nanos) throws InterruptedException {
    if (timeout < 0) {
      throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
      throw new IllegalArgumentException("nanosecond timeout value out of range");
    }

    if (nanos > 0) {
      timeout++;
    }

    wait(timeout);
  }

  public final void wait() throws InterruptedException {
    wait(0);
  }

  protected void finalize() throws Throwable {}
}

registerNatives方法

由於registerNatives方法被static塊修飾,所以在載入Object類時就會執行該方法,對應的本地方法為Java_java_lang_Object_registerNatives,如下,

JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
    (*env)->RegisterNatives(env, cls,
                            methods, sizeof(methods)/sizeof(methods[0]));
}

可以看到它間接呼叫了JNINativeInterface_結構體的方法,簡單可以看成是這樣:它乾的事大概就是將Java層的方法名和本地函式對應起來,方便執行引擎在執行位元組碼時根據這些對應關係表來呼叫C/C++函式,如下面,將這些方法進行註冊,執行引擎執行到hashCode方法時就可以通過關係表來查詢到JVM的JVM_IHashCode函式,其中()I還可以得知Java層上的型別應該轉為int型別。這個對映其實就可以看成將字串對映到函式指標。

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},
};

getClass方法

getClass方法也是個本地方法,對應的本地方法為Java_java_lang_Object_getClass,如下:

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);
    }
}

所以這裡主要就是看GetObjectClass函式了,Java層的Class在C++層與之對應的則是klassOop,所以關於類的後設資料和方法資訊可以通過它獲得。

JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj))
  JNIWrapper("GetObjectClass");
  DTRACE_PROBE2(hotspot_jni, GetObjectClass__entry, env, obj);
  klassOop k = JNIHandles::resolve_non_null(obj)->klass();
  jclass ret =
    (jclass) JNIHandles::make_local(env, Klass::cast(k)->java_mirror());
  DTRACE_PROBE1(hotspot_jni, GetObjectClass__return, ret);
  return ret;
JNI_END

hashCode方法

由前面registerNatives方法將幾個本地方法註冊可知,hashCode方法對應的函式為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

對於hashcode生成的邏輯由synchronizer.cppget_next_hash函式決定,實現比較複雜,根據hashcode的不同值有不同的生成策略,最後使用一個hash掩碼處理。

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     value = os::random() ;
  } else
  if (hashCode == 1) {
     intptr_t addrBits = 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 = intptr_t(obj) ;
  } else {
     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;
}

equals方法

這是一個非本地方法,判斷邏輯也十分簡單,直接==比較。

clone方法

由本地方法表知道clone方法對應的本地函式為JVM_Clone,clone方法主要實現物件的克隆功能,根據該物件生成一個相同的新物件(我們常見的類的物件的屬性如果是原始型別則會克隆值,但如果是物件則會克隆物件的地址)。Java的類要實現克隆則需要實現Cloneable介面,if (!klass->is_cloneable())這裡會校驗是否有實現該介面。然後判斷是否是陣列分兩種情況分配記憶體空間,新物件為new_obj,接著對new_obj進行copy及C++層資料結構的設定。最後再轉成jobject型別方便轉成Java層的Object型別。

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_Clone");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  const KlassHandle klass (THREAD, obj->klass());
  JvmtiVMObjectAllocEventCollector oam;

  if (!klass->is_cloneable()) {
    ResourceMark rm(THREAD);
    THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
  }

  const int size = obj->size();
  oop new_obj = NULL;
  if (obj->is_javaArray()) {
    const int length = ((arrayOop)obj())->length();
    new_obj = CollectedHeap::array_allocate(klass, size, length, CHECK_NULL);
  } else {
    new_obj = CollectedHeap::obj_allocate(klass, size, CHECK_NULL);
  }
  Copy::conjoint_jlongs_atomic((jlong*)obj(), (jlong*)new_obj,
                               (size_t)align_object_size(size) / HeapWordsPerLong);
  new_obj->init_mark();

  BarrierSet* bs = Universe::heap()->barrier_set();
  assert(bs->has_write_region_opt(), "Barrier set does not have write_region");
  bs->write_region(MemRegion((HeapWord*)new_obj, size));

  if (klass->has_finalizer()) {
    assert(obj->is_instance(), "should be instanceOop");
    new_obj = instanceKlass::register_finalizer(instanceOop(new_obj), CHECK_NULL);
  }

  return JNIHandles::make_local(env, oop(new_obj));
JVM_END

toString方法

邏輯是獲取class名稱加上@再加上十六進位制的hashCode。

notify方法

此方法用來喚醒執行緒,final修飾說明不可重寫。與之對應的本地方法為JVM_MonitorNotifyObjectSynchronizer::notify最終會呼叫ObjectMonitor::notify(TRAPS),這個過程是ObjectSynchronizer會嘗試當前執行緒獲取free ObjectMonitor物件,不成功則嘗試從全域性中獲取。

JVM_ENTRY(void, JVM_MonitorNotify(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_MonitorNotify");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  assert(obj->is_instance() || obj->is_array(), "JVM_MonitorNotify must apply to an object");
  ObjectSynchronizer::notify(obj, CHECK);
JVM_END

ObjectMonitor物件包含一個_WaitSet佇列物件,此物件儲存著所有處於wait狀態的執行緒,用ObjectWaiter物件表示。notify要做的事是先獲取_WaitSet佇列鎖,再取出_WaitSet佇列中第一個ObjectWaiter物件,再根據不同策略處理該物件,比如把它加入到_EntryList佇列中。然後再釋放_WaitSet佇列鎖。它並沒有釋放synchronized對應的鎖,所以鎖只能等到synchronized同步塊結束時才釋放。

void ObjectMonitor::notify(TRAPS) {
  CHECK_OWNER();
  if (_WaitSet == NULL) {
     TEVENT (Empty-Notify) ;
     return ;
  }
  DTRACE_MONITOR_PROBE(notify, this, object(), THREAD);

  int Policy = Knob_MoveNotifyee ;

  Thread::SpinAcquire (&_WaitSetLock, "WaitSet - notify") ;
  ObjectWaiter * iterator = DequeueWaiter() ;
  if (iterator != NULL) {
     TEVENT (Notify1 - Transfer) ;
     guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
     guarantee (iterator->_notified == 0, "invariant") ;
     if (Policy != 4) {
        iterator->TState = ObjectWaiter::TS_ENTER ;
     }
     iterator->_notified = 1 ;

     ObjectWaiter * List = _EntryList ;
     if (List != NULL) {
        assert (List->_prev == NULL, "invariant") ;
        assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;
        assert (List != iterator, "invariant") ;
     }

     if (Policy == 0) {       // prepend to EntryList
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
             List->_prev = iterator ;
             iterator->_next = List ;
             iterator->_prev = NULL ;
             _EntryList = iterator ;
        }
     } else
     if (Policy == 1) {      // append to EntryList
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
            // CONSIDER:  finding the tail currently requires a linear-time walk of
            // the EntryList.  We can make tail access constant-time by converting to
            // a CDLL instead of using our current DLL.
            ObjectWaiter * Tail ;
            for (Tail = List ; Tail->_next != NULL ; Tail = Tail->_next) ;
            assert (Tail != NULL && Tail->_next == NULL, "invariant") ;
            Tail->_next = iterator ;
            iterator->_prev = Tail ;
            iterator->_next = NULL ;
        }
     } else
     if (Policy == 2) {      // prepend to cxq
         // prepend to cxq
         if (List == NULL) {
             iterator->_next = iterator->_prev = NULL ;
             _EntryList = iterator ;
         } else {
            iterator->TState = ObjectWaiter::TS_CXQ ;
            for (;;) {
                ObjectWaiter * Front = _cxq ;
                iterator->_next = Front ;
                if (Atomic::cmpxchg_ptr (iterator, &_cxq, Front) == Front) {
                    break ;
                }
            }
         }
     } else
     if (Policy == 3) {      // append to cxq
        iterator->TState = ObjectWaiter::TS_CXQ ;
        for (;;) {
            ObjectWaiter * Tail ;
            Tail = _cxq ;
            if (Tail == NULL) {
                iterator->_next = NULL ;
                if (Atomic::cmpxchg_ptr (iterator, &_cxq, NULL) == NULL) {
                   break ;
                }
            } else {
                while (Tail->_next != NULL) Tail = Tail->_next ;
                Tail->_next = iterator ;
                iterator->_prev = Tail ;
                iterator->_next = NULL ;
                break ;
            }
        }
     } else {
        ParkEvent * ev = iterator->_event ;
        iterator->TState = ObjectWaiter::TS_RUN ;
        OrderAccess::fence() ;
        ev->unpark() ;
     }

     if (Policy < 4) {
       iterator->wait_reenter_begin(this);
     }

     // _WaitSetLock protects the wait queue, not the EntryList.  We could
     // move the add-to-EntryList operation, above, outside the critical section
     // protected by _WaitSetLock.  In practice that's not useful.  With the
     // exception of  wait() timeouts and interrupts the monitor owner
     // is the only thread that grabs _WaitSetLock.  There's almost no contention
     // on _WaitSetLock so it's not profitable to reduce the length of the
     // critical section.
  }

  Thread::SpinRelease (&_WaitSetLock) ;

  if (iterator != NULL && ObjectMonitor::_sync_Notifications != NULL) {
     ObjectMonitor::_sync_Notifications->inc() ;
  }
}

notifyAll方法

與notify方法類似,只是在取_WaitSet佇列時不是取第一個而是取所有。

wait方法

wait方法是讓執行緒等待,它對應的本地方法是JVM_MonitorWait,間接呼叫了ObjectSynchronizer::wait,與notify對應,它也是對應呼叫ObjectMonitor物件的wait方法。該方法較長,這裡不貼出來了,大概就是建立一個ObjectWaiter物件,接著獲取_WaitSet佇列鎖將ObjectWaiter物件新增到該佇列中,再釋放佇列鎖。另外,它還會釋放synchronized對應的鎖,所以鎖沒有等到synchronized同步塊結束時才釋放。

JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
  JVMWrapper("JVM_MonitorWait");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  assert(obj->is_instance() || obj->is_array(), "JVM_MonitorWait must apply to an object");
  JavaThreadInObjectWaitState jtiows(thread, ms != 0);
  if (JvmtiExport::should_post_monitor_wait()) {
    JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
  }
  ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END

finalize方法

這個方法用於當物件被回收時呼叫,這個由JVM支援,Object的finalize方法預設是什麼都沒有做,如果子類需要在物件被回收時執行一些邏輯處理,則可以重寫finalize方法。

相關文章