全局字符串常量池StringTable


以JDK7為例來分析

1、找到openjdk\jdk\src\share\native\java\lang\String.c文件,Java_java_lang_String_intern方法便對象java程序中的String.intern方法

JNIEXPORT jobject JNICALL
Java_java_lang_String_intern(JNIEnv *env, jobject this)
{
    return JVM_InternString(env, this);
}

2、找到openjdk\hotspot\src\share\vm\prims\jvm.cpp文件,找到JVM_InternString方法

// String support
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

3、StringTable::intern方法便是核心,在openjdk\hotspot\src\share\vm\classfile\symbolTable.cpp中找到

oop StringTable::intern(oop string, TRAPS)
{
  if (string == NULL) return NULL;
  ResourceMark rm(THREAD);
  int length;
  Handle h_string (THREAD, string);
  jchar* chars = java_lang_String::as_unicode_string(string, length);
// 調用了當前symbolTable.cpp文件中的重載方法 oop result
= intern(h_string, chars, length, CHECK_NULL); return result; }

其實看自帶的注釋知道,在the_table中能找到字符串實例就返回,找不到就將字符串實例引用添加到the_table中;the_table是symbolTable.cpp中維護的全局變量

oop StringTable::intern(Handle string_or_null, jchar* name, int len, TRAPS) {
  unsigned int hashValue = java_lang_String::hash_string(name, len);
  int index = the_table()->hash_to_index(hashValue);
  oop string = the_table()->lookup(index, name, len, hashValue);

  // Found
  if (string != NULL) return string;

  // Otherwise, add to symbol to table
  return the_table()->basic_add(index, string_or_null, name, len,
                                hashValue, CHECK_NULL);
}

再看看,沒找到字符串時添加到全局字符串常量池的代碼,發現本質是一個HashtableEntry

oop StringTable::basic_add(int index, Handle string_or_null, jchar* name, int len, unsigned int hashValue, TRAPS) {
  debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
  assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
         "proposed name of symbol must be stable");

  Handle string;
  // try to reuse the string if possible
  if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) {
    string = string_or_null;
  } else {
    string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
  }

  // Allocation must be done before grapping the SymbolTable_lock lock
  MutexLocker ml(StringTable_lock, THREAD);

  assert(java_lang_String::equals(string(), name, len),
         "string must be properly initialized");

  // 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>* entry = new_entry(hashValue, string()); add_entry(index, entry); return string();
}

basic_add方法中的條件判斷!string_or_null.is_null()為true,!JavaObjectsInPerm為true,所以並不會進行字符串的復制,而是通過HashtableEntry對象封裝原字符串的hash值和指向源字符串的句柄,添加到StringTable對應bucket的鏈表中,並返回指向原字符串句柄。其中變量JavaObjectsInPerm默認為false,查看openjdk\hotspot\src\share\vm\runtime\globals.hpp文件:

  develop(bool, JavaObjectsInPerm, false,                                   \
          "controls whether Classes and interned Strings are allocated"     \
          "in perm.  This purely intended to allow debugging issues"        \
          "in production.")       

大概含義是,控制Class實例和全局字符串常量池是否存儲在永久代,默認值為false,表示會存儲在java heap上。

可以參考:http://www.shellsec.com/news/39419.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM