2012-12-08 2 views
8

Object 클래스가 어떻게 구현되어 있는지 궁금합니다. 예Object 클래스는 어떻게 구현됩니까 (hashCode 및 내부 필드와 같은 메서드)?

  1. 메소드 해시 코드() 또는 기다려()를 들어
  2. 어떻게 표시되는 내부 상태이다. 예를 들어, 객체의 wait()을 호출 한 스레드를 저장하기위한 내장 (intrinsic) 잠금 또는 데이터 구조.

이러한 것을 찾으려면 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); 
    } 
} 

내 이해

는 방법 [] 배열은 객체의 메소드의 기본 구현 사이의 매핑을 정의합니다. 예를 들어, Object의 hashCode()는 JVM_IHashCode 함수에 매핑됩니다. JVM_IHashCode는 \ openjdksrc \ hotspot \ src \ share \ vm \ prims \ jvm.cpp에 구현됩니다. 그리고 여기에 내 첫 번째 질문입니다. 이것이 VM 자체의 일부인 이유 (이미 \ openjdksrc \ hotspot \ src \ share \ vm에 정의되어 있습니다)? 그러나이 JVM_IHashCode의 코드 이동을 할 수 있습니다 : 객체가 null의 경우

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 

왜 우리가 여기에 0을 반환? NPE가 던져 져야한다고 생각합니다. 그렇지 않으면 FastHashCode가 \ openjdksrc \ hotspot \ src \ share \ vm \ runtime \ synchronizer.cpp에서 호출되고 결국 일부 시점에서 실제 값을 계산하는 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 \ 핫스팟 \의 SRC \ 공유에 \ VM \ private 필드에 markOop을 갖고있는 것 같아요 을 oop.hpp \ 죄송합니다. 그렇다면 코드의 나머지 부분에서 실제로 언급되는 "oop"은 무엇입니까? 그리고 markOop 정의를 어디에서 찾을 수 있습니까? 나는 해당 발견 : \ VM \ 죄송합니다 \ markOop.hpp \ openjdksrc \ 핫스팟 \ SRC \ 공유에

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

하지만 열거의 전체이며, 해시 값이 할 수있는 필드를 찾을 수 없습니다 저장할 수 있습니다. 누군가가 내 질문 중 적어도 일부에 대답 할 수 있다면 나는 매우 감사 할 것입니다. 감사!

+0

는 null''의 해시 코드는 실제로 제로 있어야하는데 : http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/System.html#identityHashCode (java.lang.Object) – int3

답변

2

자바 객체의 해시 코드는 일단 계산되면 객체 헤더에 저장됩니다.

핫스팟에서 http://hunmr.blogspot.com/2012/08/java-performance-tunning.html

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

/SRC/주/VM/죄송합니다/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) 
// 
+1

참조 : "OOP"는 "일반 객체 포인터"를 의미합니다. –

+0

고마워요! 내 머리 속에 몇 가지 질문이 추가되었습니다. 나는 당신이 객체 헤더가 8 바이트를 필요로한다고 말하는 웹 사이트에서 읽었다. 16 바이트 (4 바이트의 각 라인 * 4 라인) 인 것처럼 보입니다. 나는 또한 일부 분야의 크기에 대해 궁금합니다. 왜 해시가 25 비트일까요? 왜 2 비트 잠금입니까? 나는 그것이 자물쇠를 위해 단지 1 비트를 가지고있는 것으로 충분할 것이라고 생각한다. 나이, 에포크 및 프로모션 비트는 무엇입니까? – Janek

+0

@Janek, 좋은 질문입니다. "정상적인"객체 상태와 "편향된"객체 상태는 상호 배타적이라고 생각합니다. 또한 "CMD 무료"및 "CMS 승격"에 대한 것입니다. 나이는 생성 기반 메모리 관리를 구현하는 데 사용됩니다. epoch? promo_bits? 나는 모른다. 모든 대답은 소스 코드에 있습니다. :) – whunmr

관련 문제