字符串常量池的设计思想
字符串的分配和其他的对象分配一样耗费高昂的时间与空间代价,作为最基础的数据类型大量频繁的创建字符串极大程度地
影响程序的性能。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化,为字符串开辟一个字符串常量池类似于缓存区。
创建字符串常量时,首先坚持字符串常量池是否存在该字符串若存在该字符串返回引用实例,不存在则实例化该字符串并放入池中。
实现该优化的基础是因为字符串是不可变的,可以不用担心数据冲突进行共享运行时实例创建的全局字符串常量池中有一个表,
总是为池中每个唯一的字符串对象维护一个引用,这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。
字符串常量池在哪里
在分析字符串常量池的位置时,首先了解一下堆、栈、方法区:
堆
存储的是对象,每个对象都包含一个与之对应的class,JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定。
栈
每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),每个栈中的数据(原始类型和对象引用)都是私有的。
栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失
方法区
跟堆一样,被所有的线程共享,方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量
字符串常量池则存在于方法区
实例
1 | String str1 = “abc”; |
str1,str2,str3,str4,str5存放在栈中,abc存放在常量池,new String(“abc”)存放在堆中
字符串对象的创建
面试题:String str4 = new String(“abc”) 创建多少个对象?
在常量池中查找是否有“abc”对象,有则返回对应的引用实例,没有则创建对应的实例对象。在堆中 new 一个 String(“abc”) 对象,将对象地址赋值给str4,创建一个引用。
所以,常量池中没有“abc”字面量则创建两个对象,否则创建一个对象,以及创建一个引用。
1 | String str1 = new String("A"+"B") ; 会创建多少个对象? |