前言先给出结论,不同点用红标
jdk1.6
)1)字符串数据存储在永久的世代中,new发出的字符串数据存储在堆中,字符串常量池中只存储指针数据
)2) new中出现的字符串在调用String.intern后:
如果没有与字符串常量池对应的数据,则堆中的字符串数据将复制到永久层代,并返回字符串常量池中的指针。
如果字符串常量池中有适当的数据,则直接返回字符串常量池中的指针
jdk1.7
)字符串数据存储在堆中,从new出来的字符串数据存储在堆中,字符串常量池中只存储指针数据
)2) new中出现的字符串在调用String.intern后:
如果没有与字符串常量池对应的数据,则会将堆中字符串数据的逻辑地址复制到堆中,并返回字符串常量池中的指针。
如果字符串常量池中有适当的数据,则直接返回字符串常量池中的指针
上面的大部分内容与《深入理解Java虚拟机》一致,但唯一有疑问的是intern的实现,因此以下仅证明intern
证明流程
以jdk1.6为例
)1)首先,按照openjdk下载方法下载各个版本的openjdk源代码,找到相应版本的JDK源代码
(2)找到String.intern实现) http://Hg.open JDK.Java.net/JDK6/JDK6/hotspot/file/d9c 3790 c 85 c1/src/share/vdk
JVM_entry(jstring,JVM_internstring ) jnienv*env,jstring str ) ) JVMwrapper('JVM_internstring ' ); jvmtivmobjectalloceventcollectoroam; if(str==null )返回空值; 如果//str为NULL,则返回NULL值oopstring=JNI handles 33603360 resolve _ non _ null (str ); op result=string table :3360 intern (string,CHECK_NULL ); //StringTable.intern是具体逻辑return(jstring ) JNI handles 3360: make _ local (env,result ); JVM_END
(3)再看看StringTable.intern的实现吧。 http://Hg.open JDK.Java.net/JDK6/JDK6/hotspot/file/d9c 3790 c 85 c1/src/share/d
op字符串表:3360 intern (symbol * symbol,TRAPS ) if ) symbol==null ) return NULL; 资源标记RM (thread; int length; jhar * chars=symbol-as _ unicode (length ); 从symbol获取字符串的指针Handle string; op result=intern (字符串、chars、length、CHECK_NULL ); 返回结果; } OOP string table :3360 intern (handle string _ or _ null,jchar* name,int len,TRAPS ) unsignedinthashvalue=hash//StringTable的序列下标oop found_string=the_table ()-lookup(index,name,len,hashValue ); 查一下是否有符合StringTable的字符串数据//如果有符合的字符串数据,直接输入if(found_string!=null (返回found _ string; debug _ only (stablememorycheckersmc (name,len*sizeof ) name[0] ); 资产(! universe :3360 heap (-is _ in _ reserved ) name|| GC _ locker 33603360 is _ active ),' proposednameofsymbol handle stre //trytoreusethestringifpossibleif (! string_or_null.is_null ()! 在avaobjectsinperm|||string _ or _ null (-is _ perm () StringTable中找不到相应的字符串,但如果字符串位于永久带中,则string=string_ 堆中的字符串数据string=Java _ lang _ string 33603360 create _ tenured _ from _ unicode (name,len, 复制che een (/grabthestringtable _ lockbeforegettingthe _ table ) ) becauseitcould//changeatsafepoint.mutexlockerml //将字符串添加到字符串表中。 其中return the _ table (-basic _ add (index,string,name,len,hashValue,check_name } ),与HashMap原理几乎相同
完成,jdk1.6,new中出现的字符串在调用String.intern后:
如果没有与字符串常量池对应的数据,则堆中的字符串数据将复制到永久层代,并返回字符串常量池中的指针。
如果字符串常量池中有适当的数据,则直接返回字符串常量池中的指针
同样,从jdk1.7开始,调用intern不会复制字符串数据
那么字符串常量池是什么样的数据结构? 为什么可以同时存储字符串数据和字符串的逻辑地址?
字符串常量池在StringTable内存空间中实现,StringTable只存储指针,不存储具体数据
综上所述:
)1) jdk1.6字符串常量池并不存储实际字符串数据,而是存储在具有永久带宽的区域中(由pspermgen 33603360 allocate _ permanent分配) );
)2) jdk1.7也同样,只有字符串数据存储在堆中
参考资料
3358 Java-performance.info/string-intern-in-Java-6-7-8 /