In Java, how is the underlying algorithm of the hashCode () value of an Object implemented ?, Objecthashcode

Source: Internet
Author: User

In Java, how is the underlying algorithm of the hashCode () value of an Object implemented ?, Objecthashcode

In Java, an Object has a special method: hashcode (). hashcode () indicates a value of the int type allocated to the Object by the JVM virtual machine, JVM uses the hashcode value of an object to improve the efficiency of accessing objects in HashMap and Hashtable hash tables.

The hashCode () returned value of an Object is a simple description on the Internet: "JVM is generated based on a certain policy." What is this policy? I have a problem. When I encounter such vague things, I want to find out. Therefore, this article will explain the implementation of the local hashCode () method, it also helps you understand hashCode.

Based on the openJDK 7 source code, this article will demonstrate the secrets generated by the hashCode () of the Object in Java. I will introduce the hashcode () of the Java Object step by step () the underlying function called by the method. To better understand this process, you can download the openJDK 7 source code, view and track the source code, and understand the generation process of hashCode:

OpenJDK 7 1: http://download.java.net/Openjdk/Jdk7 (official website, slow download speed)

OpenJDK 7 2: openjdk-7-fcs-src-b147-27_jun_2011.zip (csdn users to provide resources, very good)


1. View openJDK's definition of the java. lang. Object Class and Its hashcode () method:

EnterOpenjdk \ jdk \ src \ share \ classes \ java \ langDirectory, you can seeObject. javaSource code, open, ViewHashCode ()The definition is as follows:

public native int hashCode();
That is, this method is a local method. Java will call the implementation of this method in the local keystore library. Because the Object class has a JNI method call, according to The JNI rules, the header file of JNI should be generated and executed in this directory. Javah-jni java. lang. ObjectCommand to generate Java_lang_Object.hHeader file, which will be used later

Java_lang_Object.hThe information about the hashcode method in the header file is as follows:

/* * Class:     java_lang_Object * Method:    hashCode * Signature: ()I */JNIEXPORT jint JNICALL Java_java_lang_Object_hashCode  (JNIEnv *, jobject);


2. The hashCode () method of the Object is implemented in Object. c of the c language file.

OpenOpenjdk \ jdk \ src \ share \ native \ java \ lang \Directory, ViewObject. cFile, you can seeHashCode ()Methods are registeredJVM_IHashCodeMethod pointer to handle:

# Include <stdio. h> # include <signal. h> # include <limits. h> # include "jni. h "# include" jni_util.h "# include" jvm. h "# include" java_lang_Object.h "static JNINativeMethod methods [] ={{" hashCode "," () I ", (void *) & JVM_IHashCode }, // hashcode method pointer JVM_IHashCode {"wait", "(J) V", (void *) & JVM_MonitorWait}, {"policy", "() V ", (void *) & JVM_MonitorNotify}, {"policyall", "() V", (void *) & jvm_monitorpolicyall}, {"clone ","() ljava/lang/Object; ", (void *) & JVM_Clone},}; JNIEXPORT void Merge (JNIEnv * env, jclass cls) {(* env)-> RegisterNatives (env, cls, methods, sizeof (methods)/sizeof (methods [0]);} JNIEXPORT jclass JNICALLJava_java_lang_Object_getClass (JNIEnv * env, jobject this) {if (this = NULL) {JNU_ThrowNullPointerException (env, NULL); return 0 ;}else {return (* env)-> GetObjectClass (env, this );}}

3. The JVM_IHashCode method pointer is defined in openjdk \ hotspot \ src \ share \ vm \ prims \ jvm. cpp, as follows:

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

As shown above,JVM_IHashCodeMethod calledObjectSynchronizer: FastHashCodeMethod

4. ObjectSynchronizer ::Implementation of the fashHashCode method:

ObjectSynchronizer: fashHashCode ()Method inOpenjdk \ hotspot \ src \ share \ vm \ runtime \ synchronizer. cppFile implementation, its core code implementation is as follows:

// HashCode () generation: // Possibilities: // * MD5Digest of {obj, stwRandom} // * CRC32 of {obj, stwRandom} or any linear-feedback shift register function. // * a des-or AES-style SBox [] mechanic // * One of the Phi-based schemes, such: // 2654435761 = 2 ^ 32 * Phi (golden ratio) // HashCodeValue = (uintptr_t (obj)> 3) * 2654435761) ^ GVars. stwRandom; // * A variation of Marsaglia's shift-xor RNG Scheme. // * (obj ^ stwRandom) is appealing, but can result // in undesirable regularity in the hashCode values of adjacent objects // (objects allocated back-to-back, in particle ). this coshould potentially // result in hashtable collisions and CED hashtable efficiency. // There are simple ways to "diffuse" the middle address bits over the // generated hashCode values: // static inline intptr_t get_ne Xt_hash (Thread * Self, oop obj) {intptr_t value = 0; if (hashCode = 0) {// This form uses an unguarded global Park-Miller RNG, // so it's possible for two threads to race and generate the same RNG. // On MP system we'll have lots of RW access to a global, so the // mechanic induces lots of coherency traffic. value = OS: random ();} else if (hashCode = 1) {// This variation has the property Of being stable (idempotent) // between STW operations. this can be useful in some of the 1-0 // synchronization schemes. intptr_t addrBits = intptr_t (obj)> 3; value = addrBits ^ (addrBits> 5) ^ GVars. stwRandom;} else if (hashCode = 2) {value = 1; // for sensiti1_testing} else if (hashCode = 3) {value = ++ GVars. hcSequence;} else if (hashCode = 4) {value = intptr_t (obj);} els E {// Marsaglia's xor-shift scheme with thread-specific state // This is probably the best overall implementation -- we'll // likely make this the default in future releases. 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 = 0 xBAD; assert (value! = MarkOopDesc: no_hash, "invariant"); TEVENT (hashCode: GENERATE); return value ;}// ObjectSynchronizer: Implementation of the FastHashCode method, this method will eventually return our long-awaited hashcodeintptr_t ObjectSynchronizer: FastHashCode (Thread * Self, oop obj) {if (UseBiasedLocking) {// NOTE: when places throughout the JVM do not have CT a safepoint // to be taken here, in particle most operations on perm gen // objects. however, we only eve R 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 callto // 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 shocould not be seen by VM thread here"); BiasedLocking: revoke_and_rebias (hobj, false, JavaThread: current ()); obj = hobj (); assert (! Obj-> mark ()-> has_bias_pattern (), "biases shocould 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: Random () | 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 shoshould 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: cmp Xchg_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 cocould 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 displ Aced 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 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. WE are very excited to see this sentence. We finally get the hash !!!! Return hash ;}



Well, after the complex steps above, we finally generated our hashcode. The above code is implemented in C ++ and I can't understand it, but I can make sure that:

In Java, the hashcode () returned value of an Object cannot be the memory address of the Object!

That is, the address returned by hashcode () is not the address of the object in the memory.











Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.