目錄string 的string pool是乙個固定大小的hashtable,預設值大小長度是1009.如果放進string pool的string非常多,就會造成hash衝突嚴重,從而導致鍊錶會很長,而鍊錶長了後直接會造成的影響就是當呼叫string.intern時效能會大幅下降。
使用-xx:stringtablesize可設定stringtable長度
jdk6中stringtable是固定的,就是1009長度,所以如果長兩次中的字串過多就會導致效率下降很快。stringtablesize設定沒有要求
在jdk7中,stringtable的長度預設值是60013,stringtablesize設定沒有要求。
在jdk8開始,設定stringtable的長度的話,1009是可設定的最小值。
常量與常量的拼接結果在常量池中,原理是編譯期優化
常量池中不會存在相同內容的常量。
只要其中有乙個是變數,結果就在堆中。變數拼接的理由是stringbuilder。
如果拼接的結果呼叫intern()方法,則主動將常量池中還沒有的字串物件放入池中,並返回此物件位址。
上述**的class檔案內容為:public class stringtest1
}
從位元組碼角度看:
}通過以下**我們解析字串拼接符"+"的底層實現
public void test3()
底層位元組碼反編譯後的結果為:
從反編譯結果的第9行後面看:s1 + s2 的執行細節為:(變數s是我臨時定義的)0 ldc #12 2 astore_1
3 ldc #135 astore_2
6 ldc #14 8 astore_3
9 new #5 12 dup
13 invokespecial #6 >
16 aload_1
29 getstatic #9 32 aload_3
33 aload 4
35 if_acmpne 42 (+7)
38 iconst_1
39 goto 43 (+4)
42 iconst_0
43 invokevirtual #10 46 return
stringbuilder s = new stringbuilder();
s.tostring() --> 約等於 new string("ab")
補充:在jdk5.0之後使用的是stringbuilder,在jdk5.0之前使用的是stringbuffer
那設計到字串變數的拼接都是這樣的過程嗎?不是的,請繼續往下看
public void test4()
從class檔案看:
位元組碼角度看:
發現此時沒有stringbuilder出現了。而都是用的字串常量池。0 ldc #12 2 astore_1
3 ldc #135 astore_2
6 ldc #14 8 astore_3
9 ldc #14 11 astore 4
13 getstatic #9 16 aload_3
17 aload 4
19 if_acmpne 26 (+7)
22 iconst_1
23 goto 27 (+4)
26 iconst_0
27 invokevirtual #10 30 return
下面是乙個練習
public void test5()
下面再進行一次對比:
public static void test6()
long l2 = system.currenttimemillis();
system.out.println(l2-l1); // 8635
}
兩個方法為何差距如此大呢?原因為:public static void test7()
long l2 = system.currenttimemillis();
system.out.println(l2 - l1); // 35
}
test6方法中每次迴圈都會建立乙個stringbuilder、string類(stringbuilder呼叫tostring方法會建立乙個string類)。
總結
首先看看string原始碼中intern()方法:
public native string intern();
發現其實native型別
如果不是用雙引號宣告的string物件,可以使用string提供的intern方法:intern方法會從字串常量池中查詢當前字串是否存在,若不存在就會將當前字串放入常量池中。
題目一:new string("ab")會建立幾個物件?
其位元組碼內容如下:public class stringtest3
}
可見其創造了兩個物件:字串常量池中乙個:存放」ab「;堆空間中乙個:string。0 new #2 3 dup
4 ldc #3 6 invokespecial #4 >
9 astore_1
10 return
題目而:new string("a") + new string("b")呢?
位元組碼內容如下:public class stringtest3
}
解析:0 new #2 3 dup
4 invokespecial #3 >
7 new #4 10 dup
11 ldc #5 13 invokespecial #6 >
23 ldc #825 invokespecial #6 >
35 return
物件1:new stringbuilder()
物件2 :new string("a")
物件3:常量池中的"a"
物件4:new string("b")
物件5:常量池中的」b「
深入剖析:stringbuilder的tostring():
6. 物件6:new string("ab");強調一下:tostring()的呼叫,在字串常量池中,沒有生成」ab「。不信你看位元組碼
題目三:
上題變形
總結string的intern()的使用:public class stringtest6
}
intern()使用:練習1
變形
intern()使用:練習2
JVM之top jstack分析cpu過高原因
1 用ps ef grep tomcat v3 查出tomcat執行的程序id 2 用top hp pid 查詢程序下所有執行緒的運 況 shift p 按cpu排序,shift m 按記憶體排序 3 找到cpu最高的pid,用printf x n pid 轉換為16進製制 printf x n 3...
JVM物件逃逸分析 JVM記憶體
jvm的執行模式有三種 解釋模式 interpreted mode 只使用直譯器 xint 強制jvm使用解釋模式 執行一行jvm位元組碼就編譯一行為機器碼 編譯模式 compiled mode 只使用編譯器 xcomp jvm使用編譯模式 先將所有jvm位元組碼一次編譯為機器碼,然 後一次性執行所...
原始碼分析之String
先看屬性 底層是char陣列,一目了然 可以看到,value是儲存string的內容的,即當使用string str abc 的時候,本質上,abc 是儲存在乙個char型別的陣列中的。string底層的儲存結構是乙個字元型別的陣列,同樣也是被final修飾,因此一旦這個字元陣列被建立後,value...