方法区内部包含了运行时常量池
常量池
就是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等信息
运行时常量池
把字节码文件中的常量池信息放入运行时常量池,并把里面的符号地址变为真实地址
字符串常量池StringTable的特性
利用字符串池的机制来避免重复创建字符串对象
字符串变量拼接的原理是 StringBuilder(1.8):String a = "a"; String b = "b"; String c = a + b;
字符串常量拼接的原理是 编译器优化:String c = "a" + "b";
intern
intern方法的作用就是可以主动将字符串常量池中还没有的字符串对象放入尝试将一个字符串放入StringTable中。对于程序中大量存在的字符串,尤其是存在很多重复字符串时,使用intern()可以节省内存空间。
1.6:将这个字符串对象尝试放入串池中,如果不存在就放入StringTable并返回StringTable中的地址,如果存在的话就直接返回StringTable中的地址。
1.8:尝试将字符串对象放入StringTable,如果有则并不会放入,如果没有会创建一个这个对象的引用放入StringTable(而不是直接将该字符串放入stringtable中),再把StringTable的这个引用返回。
思考:String str = new String("a") + new String("b"); 一共创建了几个对象?
对象1: new StringBuilder():凡是变量拼接都会new 一个 StringBuilder
对象2:new String("a")
对象3:常量池中的"a":在字节码中为ldc
对象4:new String("b")
对象5:常量池中的"b":在字节码中为ldc
对象6:StringBuilder的toString():new String("ab")。但toString()的调用,在字符串常量池中没有生成"ab"
StringTable 垃圾回收
-XX:+PrintStringTableStatistics 开启打印StringTable的参数
StringTable:类似于HashTable的实现(数组+链表),
每个数组个数称为桶buckets
键值对个数:number of entries
字符串常量个数:number of literals
StringTable 性能调优
1. 调整-XX:StringTableSize=桶个数
2. 考虑将字符串对象是否入池