2012-12-08 14 views
8

Sono curioso di come viene implementata la classe Object. Per esempioCome viene implementata la classe Object (metodi come hashCode e campi interni)?

  1. un metodo hashCode() o attendere()
  2. Come è lo stato interno rappresentato. Ad esempio, un blocco instrinsic o la struttura dati per la memorizzazione di thread che hanno chiamato l'attesa dell'oggetto().

Per conoscere i prezzi, ho scaricato una fonte di OpenJDK e ha iniziato a scavare in. La prima cosa, mi sono imbattuto ero \ openjdksrc \ jdk \ src \ share \ nativo \ java lang \ Oggetto \. file C, che contiene, tra gli altri:

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

e la mia comprensione, metodi array [] definisce una mappatura tra le implementazioni native di metodi dell'oggetto. Ad esempio, hashCode() dell'oggetto è mappato alla funzione JVM_IHashCode. JVM_IHashCode è implementato in \ openjdksrc \ hotspot \ src \ share \ vm \ prims \ jvm.cpp. E qui è la mia prima domanda. Perché questa è già una parte della VM stessa (è già definita in \ openjdksrc \ hotspot \ src \ share \ vm)? Ma consente di passare al codice di 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 

Perché se l'oggetto è nullo torniamo qui 0? Immagino che debba essere lanciato un NPE. In caso contrario, FastHashCode viene chiamato da \ openjdksrc \ hotspot \ src \ share \ vm \ runtime \ synchronizer.cpp e infine, in un determinato momento, viene chiamato get_next_hash che calcola il valore reale. Una volta calcolato, la domanda è dove è memorizzata?

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

Quindi la programmazione orientata agli oggetti di classe/struct (?) ha un markOop classe/struttura (?) in cui è memorizzato il valore hash. Funilly non riesco a localizzare queste classi/strutture. Tutto quello che sono riuscito a trovare era:

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

in \ openjdksrc \ hotspot \ src \ share \ vm \ oops \ oop.hpp che sembra avere markOop in un settore privato. Ma allora cos'è realmente "oop" che si riferisce al resto del codice? E dove trovare la definizione markOop? Ho trovato un corrispondente:

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

in \ openjdksrc \ hotspot \ src \ share \ vm \ oops \ markOop.hpp ma è pieno solo di enumerazioni e non riesco a trovare un campo in cui il valore hash può essere conservato Se qualcuno potesse rispondere almeno una parte delle mie domande , sarei molto grato. Grazie!

+0

Il hashCode di 'null' si suppone infatti pari a zero: http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/System.html#identityHashCode (java.lang.Object) – int3

risposta

2

Il codice hash dell'oggetto Java viene memorizzato nell'intestazione dell'oggetto, una volta calcolato.

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

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

da hotspot/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) 
// 
+1

Per riferimento: "OOP" qui significa "Puntatore di oggetto ordinario". –

+0

Grazie! Qualche altra domanda è comparsa nella mia testa. Ho letto sul sito web a cui ti riferisci che l'intestazione dell'oggetto richiede 8 byte. Qui sembra che sia 16 byte (4 byte ogni linea * 4 linee). Sono anche curioso delle dimensioni di alcuni campi. Perché hash è solo 25 bit? E perché il blocco è a 2 bit? Penso che sarebbe sufficiente avere solo 1 bit per la serratura. E quali sono i campi: età, epoca e promozioni? – Janek

+0

@Janek, buona domanda. Penso che gli stati oggetto "normale" e "parziale" siano mutuamente esclusi. e anche per "CMD free" e "CMS promoted". L'età viene utilizzata per implementare la gestione della memoria basata sulla generazione. Epoch? promo_bits? Non lo so. tutta la risposta è nel codice sorgente. :) – whunmr

Problemi correlati