前言

以JDK8为例来分析

String.java

public native String intern();

String.c

openjdk8\openjdk\jdk\src\share\native\java\lang\String.c

#include "jvm.h" #include "java_lang_String.h" JNIEXPORT jobject JNICALL Java_java_lang_String_intern(JNIEnv *env, jobject this) { return JVM_InternString(env, this); }

jvm.cpp

openjdk8\openjdk\hotspot\src\share\vm\prims\jvm.cpp

JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str)) JVMWrapper("JVM_InternString"); JvmtiVMObjectAllocEventCollector oam; if (str == NULL) return NULL; oop string = JNIHandles::resolve_non_null(str); oop result = StringTable::intern(string, CHECK_NULL); return (jstring) JNIHandles::make_local(env, result); JVM_END

StringTable::intern

openjdk8\openjdk\hotspot\src\share\vm\classfile\symbolTable.cpp中找到

oop StringTable::intern(Symbol* symbol, TRAPS) { if (symbol == NULL) return NULL; ResourceMark rm(THREAD); int length; jchar* chars = symbol->as_unicode(length); Handle string; oop result = intern(string, chars, length, CHECK_NULL); return result; }

oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) { unsigned int hashValue = hash_string(name, len); int index = the_table()->hash_to_index(hashValue); oop found_string = the_table()->lookup(index, name, len, hashValue); // Found if (found_string != NULL) { ensure_string_alive(found_string); return found_string; // 在the_table中找到字符串实例就返回 } debug_only(StableMemoryChecker smc(name, len * sizeof(name[0]))); assert(!Universe::heap()->is_in_reserved(name), "proposed name of symbol must be stable"); Handle string; // try to reuse the string if possible if (!string_or_null.is_null()) { string = string_or_null; // 上面常量池中不存在,则重用堆中的string对象 } else { string = java_lang_String::create_from_unicode(name, len, CHECK_NULL); } #if INCLUDE_ALL_GCS if (G1StringDedup::is_enabled()) { // Deduplicate the string before it is interned. Note that we should never // deduplicate a string after it has been interned. Doing so will counteract // compiler optimizations done on e.g. interned string literals. G1StringDedup::deduplicate(string()); } #endif // Grab the StringTable_lock before getting the_table() because it could // change at safepoint. oop added_or_found; { MutexLocker ml(StringTable_lock, THREAD); // Otherwise, add to symbol to table added_or_found = the_table()->basic_add(index, string, name, len, hashValue, CHECK_NULL); } ensure_string_alive(added_or_found); return added_or_found; }

StringTable::basic_add

oop StringTable::basic_add(int index_arg, Handle string, jchar* name, int len, unsigned int hashValue_arg, TRAPS) { assert(java_lang_String::equals(string(), name, len), "string must be properly initialized"); // Cannot hit a safepoint in this function because the "this" pointer can move. No_Safepoint_Verifier nsv; // Check if the symbol table has been rehashed, if so, need to recalculate // the hash value and index before second lookup. unsigned int hashValue; int index; if (use_alternate_hashcode()) { hashValue = hash_string(name, len); index = hash_to_index(hashValue); } else { hashValue = hashValue_arg; index = index_arg; } // Since look-up was done lock-free, we need to check if another // thread beat us in the race to insert the symbol. oop test = lookup(index, name, len, hashValue); // calls lookup(u1*, int) if (test != NULL) { // Entry already added return test; } HashtableEntry<oop, mtSymbol>* entry = new_entry(hashValue, string()); add_entry(index, entry); return string(); }

hashtable.hpp

openjdk8\openjdk\hotspot\src\share\vm\utilities\hashtable.hpp

template <class T, MEMFLAGS F> class HashtableEntry : public BasicHashtableEntry<F> { friend class VMStructs; private: T _literal; // ref to item in table. public: // Literal T literal() const { return _literal; } T* literal_addr() { return &_literal; } void set_literal(T s) { _literal = s; } HashtableEntry* next() const { return (HashtableEntry*)BasicHashtableEntry<F>::next(); } HashtableEntry** next_addr() { return (HashtableEntry**)BasicHashtableEntry<F>::next_addr(); } };

hashtable.inline.hpp

template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::new_entry(unsigned int hashValue, T obj) {
HashtableEntry<T, F>* entry;

entry = (HashtableEntry<T, F>*)BasicHashtable<F>::new_entry(hashValue);
entry->set_literal(obj);
return entry;
}

template <MEMFLAGS F> inline void BasicHashtable<F>::add_entry(int index, BasicHashtableEntry<F>* entry) { entry->set_next(bucket(index)); _buckets[index].set_entry(entry); ++_number_of_entries; }