马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
##String native方法
public native String intern();
1. intern() 方法在 Java 中的作用
在 Java 中,String#intern() 方法是一个本地方法,用于确保字符串常量池中只有一个字符串的实例。当你调用 intern() 方法时,它会查抄字符串常量池中是否已经存在一个雷同的字符串。如果存在,它返回池中的字符串引用,否则将字符串添加到常量池中并返回该引用。
2. JVM_InternString C++ 实现
JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str)) 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(THREAD, result); JVM_END
这个 C++ 函数是 String#intern() 的本地实现。它首先获取 jstring 类型的字符串引用,然后通过 StringTable::intern 来查找或插入字符串到字符串常量池中。如果字符串已经存在,则返回池中的字符串引用,否则将其插入池中。
3. StringTable::intern 方法
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, CHECK_NULL); oop result = intern(h_string, chars, length, CHECK_NULL); return result; }
- 这里的 intern 方法接受一个 oop(对象指针)类型的字符串,并将其转换为 Unicode 字符数组。然后它调用另一个重载的 intern 方法,现实执行字符串查找或插入操纵。
- ResourceMark 是为了确保在执行期间分配的资源能够在竣事时被采取。
4. 字符串查找和插入 (do_lookup 和 do_intern)
在 StringTable::do_lookup 中,我们执行的是对字符串常量池的查找操纵。它首先会实验在本地表中查找该字符串。如果找到了,它就返回找到的字符串对象(found_string)。
oop StringTable::do_lookup(const jchar* name, int len, uintx hash) { Thread* thread = Thread::current(); StringTableLookupJchar lookup(thread, hash, name, len); StringTableGet stg(thread); bool rehash_warning; _local_table->get(thread, lookup, stg, &rehash_warning); update_needs_rehash(rehash_warning); return stg.get_res_oop(); }
- 在本地表(_local_table)中查找字符串时,它会计算字符串的哈希值并查找对应的条目。
- 如果查找到了字符串,stg.get_res_oop() 会返回字符串对象(oop)。
5. 字符串插入操纵 (do_intern)
如果在查找时未找到该字符串,do_intern 会创建一个新的字符串对象并将其插入到常量池中。
oop StringTable::do_intern(Handle string_or_null_h, const jchar* name, int len, uintx hash, TRAPS) { HandleMark hm(THREAD); // cleanup strings created Handle string_h; if (!string_or_null_h.is_null()) { string_h = string_or_null_h; } else { string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL); } assert(java_lang_String::equals(string_h(), name, len), "string must be properly initialized"); assert(len == java_lang_String::length(string_h()), "Must be same length"); // Check for deduplication if (StringDedup::is_enabled()) { StringDedup::notify_intern(string_h()); } StringTableLookupOop lookup(THREAD, hash, string_h); StringTableGet stg(THREAD); bool rehash_warning; do { WeakHandle wh(_oop_storage, string_h); if (_local_table->insert(THREAD, lookup, wh, &rehash_warning)) { update_needs_rehash(rehash_warning); return wh.resolve(); } if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) { update_needs_rehash(rehash_warning); return stg.get_res_oop(); } } while (true); }
- 创建字符串对象:如果传入的字符串为空,它会通过 create_from_unicode 创建一个新的字符串对象。
- 插入字符串:然后通过 WeakHandle 将字符串插入到本地表中。
- 查抄重复:如果存在重复的字符串,它会通过循环保证字符串只有一个实例。如果另一个线程已经插入了雷同的字符串,当前线程会发现并直接返回该字符串。
6. 字符串表的初始化 (create_table)
在 JVM 启动时,字符串常量池会通过 StringTable::create_table 方法来初始化本地表。
void StringTable::create_table() { size_t start_size_log_2 = ceil_log2(StringTableSize); _current_size = ((size_t)1) << start_size_log_2; log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", _current_size, start_size_log_2); _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN); _oop_storage = OopStorageSet::create_weak("StringTable Weak", mtSymbol); _oop_storage->register_num_dead_callback(&gc_notification); }
- StringTableSize:这是常量池的初始巨细,它会根据设置举行调解。
- StringTableHash:用于实现字符串常量池的哈希表。
- OopStorageSet:用于存储字符串对象,WeakHandle 确保对象在垃圾采取时不会被误删除。
总结
C++源码中清楚地展示了怎样通过 StringTable 管理字符串常量池。intern() 方法的核心逻辑包括查找、插入和确保字符串唯一性的操纵。不同的函数(如 do_lookup, do_intern)和结构(如 WeakHandle, StringTableHash)确保了线程安全、性能和内存管理。
##C++源码
##字符串表查找字符串
- JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str))
- 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(THREAD, result);
- JVM_END
复制代码 ##
- 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,
- CHECK_NULL);
- oop result = intern(h_string, chars, length, CHECK_NULL);
- return result;
- }
复制代码 ##
- oop StringTable::intern(Handle string_or_null_h, const jchar* name, int len, TRAPS) {
- // shared table always uses java_lang_String::hash_code
- unsigned int hash = java_lang_String::hash_code(name, len);
- oop found_string = lookup_shared(name, len, hash);
- if (found_string != NULL) {
- return found_string;
- }
- if (_alt_hash) {
- hash = hash_string(name, len, true);
- }
- found_string = do_lookup(name, len, hash);
- if (found_string != NULL) {
- return found_string;
- }
- return do_intern(string_or_null_h, name, len, hash, THREAD);
- }
复制代码 ##从本地表查找
- oop StringTable::do_lookup(const jchar* name, int len, uintx hash) {
- Thread* thread = Thread::current();
- StringTableLookupJchar lookup(thread, hash, name, len);
- StringTableGet stg(thread);
- bool rehash_warning;
- _local_table->get(thread, lookup, stg, &rehash_warning);
- update_needs_rehash(rehash_warning);
- return stg.get_res_oop();
- }
复制代码 ##在本地表没有找到,则创建一个新的插入到本地表
- oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
- int len, uintx hash, TRAPS) {
- HandleMark hm(THREAD); // cleanup strings created
- Handle string_h;
- if (!string_or_null_h.is_null()) {
- string_h = string_or_null_h;
- } else {
- string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
- }
- assert(java_lang_String::equals(string_h(), name, len),
- "string must be properly initialized");
- assert(len == java_lang_String::length(string_h()), "Must be same length");
- // Notify deduplication support that the string is being interned. A string
- // must never be deduplicated after it has been interned. Doing so interferes
- // with compiler optimizations done on e.g. interned string literals.
- if (StringDedup::is_enabled()) {
- StringDedup::notify_intern(string_h());
- }
- StringTableLookupOop lookup(THREAD, hash, string_h);
- StringTableGet stg(THREAD);
- bool rehash_warning;
- do {
- // Callers have already looked up the String using the jchar* name, so just go to add.
- WeakHandle wh(_oop_storage, string_h);
- // The hash table takes ownership of the WeakHandle, even if it's not inserted.
- if (_local_table->insert(THREAD, lookup, wh, &rehash_warning)) {
- update_needs_rehash(rehash_warning);
- return wh.resolve();
- }
- // In case another thread did a concurrent add, return value already in the table.
- // This could fail if the String got gc'ed concurrently, so loop back until success.
- if (_local_table->get(THREAD, lookup, stg, &rehash_warning)) {
- update_needs_rehash(rehash_warning);
- return stg.get_res_oop();
- }
- } while(true);
- }
复制代码 ##jvm在初始化的时候,调用create_table生成本地表。
- if (UseSharedSpaces) {
- // Read the data structures supporting the shared spaces (shared
- // system dictionary, symbol table, etc.). After that, access to
- // the file (other than the mapped regions) is no longer needed, and
- // the file is closed. Closing the file does not affect the
- // currently mapped regions.
- MetaspaceShared::initialize_shared_spaces();
- StringTable::create_table();
- } else
- #endif
- {
- SymbolTable::create_table();
- StringTable::create_table();
- }
复制代码- void StringTable::create_table() {
- size_t start_size_log_2 = ceil_log2(StringTableSize);
- _current_size = ((size_t)1) << start_size_log_2;
- log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
- _current_size, start_size_log_2);
- _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN);
- _oop_storage = OopStorageSet::create_weak("StringTable Weak", mtSymbol);
- _oop_storage->register_num_dead_callback(&gc_notification);
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |