簡書 占小狼
轉載請注明原創(chuàng)出處苍鲜,謝謝入热!
String.intern()原理
String.intern()是一個Native方法,底層調用C++的 StringTable::intern
方法拣宰,源碼注釋:當調用 intern 方法時遵绰,如果常量池中已經該字符串,則返回池中的字符串忠蝗;否則將此字符串添加到常量池中现横,并返回字符串的引用。
package com.ctrip.ttd.whywhy;
class Test {
public static void main(String args[]) {
String s1 = new StringBuilder().append("String").append("Test").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder().append("ja").append("va").toString();
System.out.println(s2.intern() == s2);
}
}
在 JDK6 和 JDK7 中結果不一樣:
1阁最、JDK6的執(zhí)行結果:false false
對于這個結果很好理解戒祠。在JDK6中,常量池在永久代分配內存速种,永久代和Java堆的內存是物理隔離的姜盈,執(zhí)行intern方法時,如果常量池不存在該字符串配阵,虛擬機會在常量池中復制該字符串馏颂,并返回引用示血,所以需要謹慎使用intern方法,避免常量池中字符串過多饱亮,導致性能變慢矾芙,甚至發(fā)生PermGen內存溢出舍沙。
2近上、JDK7的執(zhí)行結果:true false
對于這個結果就有點懵了。在JDK7中拂铡,常量池已經在Java堆上分配內存壹无,執(zhí)行intern方法時,如果常量池已經存在該字符串感帅,則直接返回字符串引用斗锭,否則復制該字符串對象的引用到常量池中并返回,所以在JDK7中失球,可以重新考慮使用intern方法岖是,減少String對象所占的內存空間。
對于變量s1实苞,常量池中沒有 "StringTest" 字符串豺撑,s1.intern() 和 s1都是指向Java對象上的String對象。
對于變量s2黔牵,常量池中一開始就已經存在 "java" 字符串聪轿,所以 s2.intern() 返回常量池中 "java" 字符串的引用。
String.intern()性能
常量池底層使用StringTable數(shù)據(jù)結構保存字符串引用猾浦,實現(xiàn)和HashMap類似陆错,根據(jù)字符串的hashcode定位到對應的數(shù)組,遍歷鏈表查找字符串金赦,當字符串比較多時音瓷,會降低查詢效率。
在JDK6中夹抗,由于常量池在PermGen中绳慎,受到內存大小的限制,不建議使用該方法兔朦。
在JDK7偷线、8中,可以通過-XX:StringTableSize參數(shù)StringTable大小沽甥,下面通過幾個測試用例看看intern方法的性能声邦。
public class StringTest {
public static void main(String[] args) {
System.out.println(cost(1000000));
}
public static long cost(int num) {
long start = System.currentTimeMillis();
for (int i = 0; i < num; i++) {
String.valueOf(i).intern();
}
return System.currentTimeMillis() - start;
}
}
執(zhí)行一百萬次intern()方法,不同StringTableSize的耗時情況如下:
1摆舟、-XX:StringTableSize=1009亥曹, 平均耗時23000ms邓了;
2、-XX:StringTableSize=10009媳瞪, 平均耗時2200ms骗炉;
3、-XX:StringTableSize=100009蛇受, 平均耗時200ms句葵;
4、默認情況下兢仰,平均耗時400ms乍丈;
在默認StringTableSize下,執(zhí)行不同次intern()方法的耗時情況如下:
1把将、一萬次轻专,平均耗時5ms;
2察蹲、十萬次请垛,平均耗時25ms;
3洽议、五十萬次宗收,平均耗時130ms;
4绞铃、一百萬次镜雨,平均耗時400ms;
5儿捧、五百萬次荚坞,平均耗時5000ms;
6菲盾、一千萬次颓影,平均耗時15000ms;
從這些測試數(shù)據(jù)可以看出懒鉴,盡管在Java 7以上對intern()做了細致的優(yōu)化诡挂,但其耗時仍然很顯著,如果無限制的使用intern()方法临谱,將導致系統(tǒng)性能下降璃俗,不過可以將有限值的字符串放入常量池,提高內存利用率悉默,所以intern()方法是一把雙刃劍城豁。
END。
我是占小狼抄课。
在魔都艱苦奮斗唱星,白天是上班族雳旅,晚上是知識服務工作者。
如果讀完覺得有收獲的話间聊,記得關注和點贊哦攒盈。
非要打賞的話,我也是不會拒絕的哎榴。