全局字符串常量池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

posted @   小菜变大鸟  阅读(2031)  评论(0)    收藏  举报
(评论功能已被禁用)
点击右上角即可分享
微信分享提示