发布于2021-05-29 22:58 阅读(797) 评论(0) 点赞(24) 收藏(5)
先给出结论,不同点用红标
jdk1.6
(1)字符串数据存储在永久代,new出来的字符串数据存储在堆,字符串常量池仅存储指针数据
(2)new出来的字符串调用String.intern后:
若字符串常量池中没有相应的数据,则堆中的字符串数据会被拷贝到永久代,并返回字符串常量池中的指针;
若字符串常量池中有相应的数据,直接返回字符串常量池中的指针
jdk1.7
(1)字符串数据存储在堆,new出来的字符串数据存储在堆,字符串常量池仅存储指针数据
(2)new出来的字符串调用String.intern后:
若字符串常量池中没有相应的数据,则堆中的字符串数据的逻辑地址会被拷贝到堆,并返回字符串常量池中的指针;
若字符串常量池中有相应的数据,直接返回字符串常量池中的指针
上面大部分内容都跟《深入理解Java虚拟机》一致,唯一有疑惑的是intern的实现,所以下面仅证明intern
以jdk1.6为例
(1)先按照openJDK之如何下载各个版本的openJDK源码找出相应版本的jdk源码
(2)找到String.intern的实现:http://hg.openjdk.java.net/jdk6/jdk6/hotspot/file/d9c3790c85c1/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; // 如果str为NULL,则直接返回NULL值
- oop string = JNIHandles::resolve_non_null(str);
- oop result = StringTable::intern(string, CHECK_NULL); // StringTable.intern实现具体逻辑
- return (jstring) JNIHandles::make_local(env, result);
- JVM_END
(3)再查看一下StringTable.intern的实现:http://hg.openjdk.java.net/jdk6/jdk6/hotspot/file/d9c3790c85c1/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); // 根据symbol获取字符串的指针
- 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); // hash字符串数据
- int index = the_table()->hash_to_index(hashValue); // 映射到StringTable的数组下标
- oop found_string = the_table()->lookup(index, name, len, hashValue); // 查一下StringTable中是否有相应的字符串数据
-
- // 如果有相应的字符串数据,则直接返回
- if (found_string != NULL) return found_string;
-
- 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())) {
- // 如果StringTable找不到相应的字符串,但字符串又存在永久带里,则直接复用
- string = string_or_null;
- } else {
- // 永久带分配一块新空间,拷贝一份堆中的字符串数据
- string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
- }
-
- // Grab the StringTable_lock before getting the_table() because it could
- // change at safepoint.
- MutexLocker ml(StringTable_lock, THREAD);
-
- // 将字符串添加到StringTable,这里跟HashMap的原理差不多
- return the_table()->basic_add(index, string, name, len,
- hashValue, CHECK_NULL);
- }
证毕,jdk1.6,new出来的字符串调用String.intern后:
若字符串常量池中没有相应的数据,则堆中的字符串数据会被拷贝到永久代,并返回字符串常量池中的指针;
若字符串常量池中有相应的数据,直接返回字符串常量池中的指针
同理也能证明,jdk1.7之后,调用intern并不会拷贝字符串数据
那么问题来了,字符串常量池是什么样的数据结构?为什么既可以存字符串数据,又可以存字符串的逻辑地址?
字符串常量池是通过StringTable+内存空间实现的,StringTable仅存储指针,不存储具体的数据
综上:
(1)jdk1.6中所谓的字符串常量池,并不存储实际的字符串数据,字符串数据存储在永久带的某块区域(通过PSPermGen::allocate_permanent进行分配);
(2)jdk1.7同理,只是字符串数据存储在堆中
参考资料:
http://java-performance.info/string-intern-in-java-6-7-8/
原文链接:https://blog.csdn.net/qq_19648191/article/details/117358082
作者:我是不是很美
链接:http://www.javaheidong.com/blog/article/207904/35686d75cef65f5326f1/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!