JVM字符串常量池會進行垃圾回收嗎?
會,但是對方法區(qū)的回收“成績”比較難以令人滿意,Java虛擬機規(guī)范中確實說過可以不要求虛擬機在方法區(qū)實現(xiàn)垃圾回收,而字符串常量池在方法區(qū)中。
假設一個字符串"everor"已經(jīng)進入了常量池,但是當前系統(tǒng)中沒有一個String對象引用常量池中的"everor"常量(即String str = new String("everor");),也沒有其他地方引用了這個字面量(即String str = "everor";),如果這個時候發(fā)生了內(nèi)存回收,而且有必要的話,這個"everor"常量就會被系統(tǒng)清理出常量池。
在HotSpot虛擬機中,方法區(qū)又被稱為永久代,永久代這個概念在其它虛擬機(如BEA JRockit、IBM J9等)中是不存在的。但是使用永久代來實現(xiàn)方法區(qū),并不是一個好主意,因為這樣更容易遇到內(nèi)存溢出問題。從JDK1.7開始,逐步使用元空間(MetaSpace)代替永久代的概念。元空間的內(nèi)存大小取決于本地內(nèi)存大小。元空間代替永久代,并不意味著字符串常量池就到了元空間,而是移到了堆中。
延伸:何時將字符串對象引用放入字符串常量池?
字符串常量池存放的是字符串對象的引用,字符串本身是一個對象,而對象是存放到堆中。當使用
String str1 = "hello";
String str2 = "hello";
時,首先會看字符串常量池中是否已經(jīng)有對“hello”字符串對象的引用,如果有,就返回池中的實例引用,如果不存在,就會實例化一個字符串到堆中,再在池中存一個對該字符串的引用。因此str1和str2指向的是同一個字符串對象。Java能夠做這樣的優(yōu)化,是因為字符串是不可變的,可以不擔心數(shù)據(jù)沖突進行共享。
而當使用
String str3 = new String("hello");
時,不管字符串常量池中是否已經(jīng)有hello字符串的引用,都會在堆中創(chuàng)建一個字符串,str3指向堆中的字符串,因此str3和str1 str2不是指向同一個對象。
當使用
String str4 = str3.intern();
時,intern()方法表示如果str3的字符串在池中有,就返回池中的引用,否則在池中創(chuàng)建一個引用,再返回該引用,因此str4 str1 str2指向的是同一個字符串對象。
參考
-《深入理解Java虛擬機》