JVM學(xué)習(xí)筆記10(StringTable)

StringTable

String的基本特性

●?String:字符串,使用一對""引起來表示米间。
●?String聲明為final的, 不可被繼承
●?String實(shí)現(xiàn)了Serializable接口:表示字符串是支持序列化的。實(shí)現(xiàn)了Comparable接口:表示String可以比較大小
●?String在jdk8及以前內(nèi)部定義了final char value[]用于存儲字符串?dāng)?shù)據(jù)赂苗。jdk9時改為byte []
●?String:代表不可變的字符序列贮尉。簡稱:不可變性拌滋。
???當(dāng)對字符串重新賦值時,需要重寫指定內(nèi)存區(qū)域賦值猜谚,不能使用原有的value進(jìn)行賦值败砂。
???當(dāng)對現(xiàn)有的字符串進(jìn)行連接操作時,也需要重新指定內(nèi)存區(qū)域賦值魏铅,不能使用原有的value進(jìn)行賦值昌犹。
???當(dāng)調(diào)用String的replace ()方法修改指定字符或字符串時,也需要重新指定內(nèi)存區(qū)域賦值览芳,不能使用原有的value進(jìn)行賦值斜姥。
●?通過字面量的方式(區(qū)別于new)給一個字符串賦值,此時的字符串值聲明在字符串常量池中沧竟。
●?字符串常量池中是不會存儲相同內(nèi)容的字符串的铸敏。
??string的String Pool 是一個固定大小的Hashtable,默認(rèn)值大小長度是1009屯仗。如果放進(jìn)String Pool 的String非常多搞坝,就會造成Hash沖突嚴(yán)重,從而導(dǎo)致鏈表會很長魁袜,而鏈表長了后直接會造成的影響就是當(dāng)調(diào)用String.intern時性能會大幅下降桩撮。
??使用-Xx: StringTableSize可設(shè)置StringTable的長度
??在jdk6中StringTable是固定的,就是1009的長度峰弹,所以如果常量池中的字符串過多就會導(dǎo)致效率下降很快店量。StringTableSize設(shè)置沒有要求
??在jdk7中,StringTable的長度默認(rèn)值是60013
??在jdk8開始鞠呈,StringTable的長度1009是可設(shè)置的最小值融师。


String的內(nèi)存分配

●?在Java語言中有8種基本數(shù)據(jù)類型和一種比較特殊的類型String。這些類型為了使它們在運(yùn)行過程中速度更快蚁吝、更節(jié)省內(nèi)存旱爆,都提供了一種常量池的概念舀射。
●?常量池就類似一個Java系統(tǒng)級別提供的緩存。8種基本數(shù)據(jù)類型的常量池都是系統(tǒng)協(xié)調(diào)的怀伦,String類型的常量池比較特殊脆烟。它的主要使用方法有兩種。
???直接使用雙引號聲明出來的String對象會直接存儲在常量池中房待。
?????比如:String info = "atguigu. com";
???如果不是用雙引號聲明的String對象邢羔,可以使用String提供的intern()方法。
●?Java 6及以前桑孩,字符串常量池存放在永久代拜鹤。
●?Java 7中Oracle的工程師對字符串池的邏輯做了很大的改變,即將字符串常量池的位置調(diào)整到Java堆內(nèi)流椒。
???所有的字符串都保存在堆(Heap)中敏簿,和其他普通對象一樣,這樣可以讓你在進(jìn)行調(diào)優(yōu)應(yīng)用時僅需要調(diào)整堆大小就可以了镣隶。
???字符串常量池概念原本使用得比較多极谊,但是這個改動使得我們有足夠的理由讓我們重新考慮在Java 7中使用String. intern()。
●?Java8元空間安岂,字符串常量在堆



String的基本操作

案例1:

常量池中對象的個數(shù):


Java語言規(guī)范里要求完全相同的字符串字面量轻猖,應(yīng)該包含同樣的Unicode字符序列(包含同一份碼點(diǎn)序列的常量),并且必須是指向同一個String類實(shí)例域那。

案例2:


字符串拼接操作

1.常量與常量的拼接結(jié)果在常量池咙边,原理是編譯期優(yōu)化
2.常量池中不會存在相同內(nèi)容的常量。
3.只要其中有一個是變量次员,結(jié)果就在堆中败许。變量拼接的原理是StringBuilder
4.如果拼接的結(jié)果調(diào)用intern()方法,則主動將常量池中還沒有的字符串對象放入池中淑蔚,并返回此對象地址市殷。
String 字符串常量
StringBuffer 字符串變量(線程安全)
StringBuilder 字符串變量(非線程安全)


intern()的使用

如果不是用雙引號聲明的String對象,可以使用String提供的intern方法:intern方法會從字符串常量池中查詢當(dāng)前字符串是否存在刹衫,若不存在就會將當(dāng)前字符串放入常量池中醋寝。
●?比如:

String myInfo = new String("I love atguigu").intern();

也就是說,如果在任意字符串上調(diào)用String.intern方法带迟,那么其返回結(jié)果所指向的那個類實(shí)例少必須和直接以常量形式出現(xiàn)的字符串實(shí)例完全相同音羞。因此,下 列表達(dá)式的值必定是true:

("a" + "b" + "c").intern() == "abc"

通俗點(diǎn)講仓犬,Interned String 就是確保字符串在內(nèi)存里只有一份拷貝嗅绰,這樣可以節(jié)約內(nèi)存空間,加快字符串操作任務(wù)的執(zhí)行速度。注意窘面,這個值會被存放在字符串內(nèi)部池(String Intern Pool)翠语。

面試題

題目1:new String("ab")會創(chuàng)建幾個對象?
題目2:new String("a") + new String("b")呢民镜?

答案1:兩個啡专,一個是new關(guān)鍵字在堆內(nèi)存中創(chuàng)建String,另外一個是字符串常量池中的對象制圈,字節(jié)碼指令:ldc


答案2:
?對象1:new StringBuilder()
?對象2:new String("a")
?對象3:常量池中的"a"
?對象4:new String("b")
?對象5:常量池中的"b"
?深入剖析:StringBuilder的toString()方法:
??對象6:new String("ab")
??強(qiáng)調(diào)一下,toString()的調(diào)用畔况,在字符串常量池中鲸鹦,沒有生成"ab"

jdk6 VS jdk7/8

public class stringIntern1 {
    public static void main(String[] args) {
        string S = new string("1");
        s.intern();  //調(diào)用此方法之前,字符串常量池中已經(jīng)存在了“1”
        string s2 ="1";
        System.out.println(s == s2);  //  jdk6:false  jdk7/8:false  s是堆空間中的地址跷跪,s2是常量池中的地址
        string s3 = new String("1") + new string("1");  //  s3變量記錄的地址為new String("11");
        //  執(zhí)行完上一行代碼后:字符串常量池中馋嗜,是否存在“11”呢?  答案:不存在吵瞻!
        s3.intern( );  
        //  在字符串常量池中生成對象“11”葛菇。
        /*
        如何理解:
            jdk6:創(chuàng)建一個新的對象“11”,也就有新的地址
            jdk7:此時常量池中并沒有創(chuàng)建“11”橡羞,而是創(chuàng)建了一個指向堆空間中new String("11")的地址
        */
        string s4 = "11";  //  s4變量記錄的地址:上一行代碼代碼執(zhí)行時眯停,在常量池中生成的“11”的地址
        System.out.println(s3 == s4);  //  jdk6:false  jdk7/8:true
    }
}

jdk6代碼圖

jdk7代碼圖

拓展

public class stringIntern1 {
    public static void main(String[] args) {
        string s3 = new String("1") + new string("1");  //  s3變量記錄的地址為new String("11");
        //  執(zhí)行完上一行代碼后:字符串常量池中,是否存在“11”呢卿泽?  答案:不存在莺债!
        string s4 = "11";  //  在字符串常量池中生成對象“11”。
        string s5 = s3.intern( );  //  發(fā)現(xiàn)常量池中有對象“11”签夭,s5指向常量池中的對象“11”
        System.out.println(s3 == s4);  //  jdk7/8:false
        System.out.println(s5 == s4);  //  jdk7/8:true
    }
}

總結(jié)String的intern()的使用:

●?jdk1.6中齐邦,將這個字符串對象嘗試放入串池。
???如果串池中有第租,則并不會放入措拇。返回已有的串池中的對象的地址
???如果沒有,會把此對象復(fù)制一份慎宾,放入串池丐吓,并返回串池中的對象地址
●?Jdk1.7起,將這個字符串對象嘗試放入串池璧诵。
???如果串池中有汰蜘,則并不會放入。返回已有的串池中的對象的地址
???如果沒有之宿,則會把對象的引用地址復(fù)制一份族操,放入串池,并返回串池中的引用地址

練習(xí)1:

public class stringExer1 {
    public static void main(String[] args) {
        String s = new String("a") + new string("b");    //new String( "ab")
        //  在上一行代碼執(zhí)行完以后,字符串常量池中并沒有“ab”
        String s2 = s.intern();
        //  jdk6中:在串池中創(chuàng)建一個字 符串“ab”
        //  jdk8中:串池中沒有創(chuàng)建字符串"ab",而是創(chuàng)建一一個引用色难, 指向new String("ab")泼舱,將此引用返回
        System.out.println(s2 == " ab");  //  jdk6:true  jdk8:true
        System.out.println(s == "ab");  //  jdk6:false  jdk8:true
    }
}

練習(xí)2:

public class stringExer2 {
    public static void main(String[] args) {
        //  會在常量池中生成“ab”
        //  String s1 = new String("ab");  //  jdk8:false
        //  會在常量池中生成“ab”
        String s1 = new string( original: "a") + new string( original: "b");  //  jdk8:true
        s1. intern();
        String s2 = "ab";
        System.out.println(s1 == s2); 
    }
}

G1中的String去重操作

●?背景:對許多Java應(yīng)用(有大的也有小的)做的測試得出以下結(jié)果:
???堆存活數(shù)據(jù)集合里面string對象占了25%
???堆存活數(shù)據(jù)集合里面重復(fù)的String對象有13.5%
???String對象的平均長度是45
●?許多大規(guī)模的Java應(yīng)用的瓶頸在于內(nèi)存,測試表明枷莉,在這些類型的應(yīng)用里面娇昙,Java堆中存活的數(shù)據(jù)集合差不多25%是string對象。更進(jìn)一步笤妙,這里面差不多一半String對象是重復(fù)的冒掌,重復(fù)的意思是說:string1.equals(string2)=true。堆上存在重復(fù)的String對象必然是一種內(nèi)存的浪費(fèi)蹲盘。這個項(xiàng)目將在G1垃圾收集器中實(shí)現(xiàn)自動持續(xù)對重復(fù)的String對象進(jìn)行去重股毫,這樣就能避免浪費(fèi)內(nèi)存。
●?實(shí)現(xiàn)
???當(dāng)垃圾收集器工作的時候召衔,會訪問堆上存活的對象铃诬。對每一個訪問的對象都會檢查是否是候選的要去重的String對象。
???如果是苍凛,把這個對象的一個引用插入到隊(duì)列中等待后續(xù)的處理趣席。一個去重的線程在后臺運(yùn)行,處理這個隊(duì)列醇蝴。處理隊(duì)列的一個元素意味著從隊(duì)列刪除這個元素宣肚,然后嘗試去重它引用的String對象。
???使用一個hashtable來記錄所有的被String對象使用的不重復(fù)的char數(shù)組哑蔫。當(dāng)去重的時候钉寝,會查這個hashtable,來看堆上是否已經(jīng)存在一個一模一樣的char數(shù)組闸迷。
???如果存在嵌纲,String對象會被調(diào)整引用那個數(shù)組,釋放對原來的數(shù)組的引用腥沽,最終會被垃圾收集器回收掉逮走。
???如果查找失敗,char數(shù)組會被插入到hashtable,這樣以后的時候就可以共享這個數(shù)組了今阳。
●?命令行選項(xiàng)
???UseStringDeduplication (bool) :開啟String去重师溅,默認(rèn)是不開啟的,需要手動開啟盾舌。
???PrintStringDeduplicationStatistics (bool) :打印詳細(xì)的去重統(tǒng)計(jì)信息
???StringDeduplicationAgeThreshold (uintx) :達(dá)到這個年齡的String對象被認(rèn)為是去重的候選對象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末墓臭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子妖谴,更是在濱河造成了極大的恐慌窿锉,老刑警劉巖酌摇,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異嗡载,居然都是意外死亡窑多,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門洼滚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來埂息,“玉大人,你說我怎么就攤上這事遥巴∏Э担” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵挪哄,是天一觀的道長吧秕。 經(jīng)常有香客問我,道長迹炼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任颠毙,我火速辦了婚禮斯入,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛀蜜。我一直安慰自己刻两,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布滴某。 她就那樣靜靜地躺著磅摹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪霎奢。 梳的紋絲不亂的頭發(fā)上户誓,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音幕侠,去河邊找鬼帝美。 笑死,一個胖子當(dāng)著我的面吹牛晤硕,可吹牛的內(nèi)容都是我干的悼潭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼舞箍,長吁一口氣:“原來是場噩夢啊……” “哼舰褪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起疏橄,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤占拍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刷喜,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡残制,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掖疮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片初茶。...
    茶點(diǎn)故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖浊闪,靈堂內(nèi)的尸體忽然破棺而出恼布,到底是詐尸還是另有隱情,我是刑警寧澤搁宾,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布折汞,位于F島的核電站,受9級特大地震影響盖腿,放射性物質(zhì)發(fā)生泄漏爽待。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一翩腐、第九天 我趴在偏房一處隱蔽的房頂上張望鸟款。 院中可真熱鬧,春花似錦茂卦、人聲如沸何什。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽处渣。三九已至,卻和暖如春蛛砰,著一層夾襖步出監(jiān)牢的瞬間罐栈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工暴备, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悠瞬,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓涯捻,卻偏偏與公主長得像浅妆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子障癌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評論 2 354