StringTable結構以及基本調優
StringTable底層實現類似於HashTable,由數組和鏈表組成,數組又稱為桶數組。比如有這樣一段程式碼:
public class Demo4 { public static void main(String[] args) { int i = 0; System.out.println(i); } }
我們設置虛擬機參數「-Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc「,參數具體的意思是 設置堆記憶體大小為10M,輸出StringTableStatistics資訊,輸出GC細節。運行程式碼控制台會有相應的輸出,主要看下StringTable部分。默認桶的個數是60013,存儲的字元串對象個數為1752,串池中字元串常量個數為也是1752,總的佔用空間約為0.6M。上面程式碼只是輸出i,但串池中常量個數為1752,那是因為類名、方法名等這些數據也是以常量的形式存在串池中。

接著稍微改動程式碼:
public class Demo4 { public static void main(String[] args) { int i = 0; // 往串池中添加100個字元串 for (int j = 0; j < 100; j++) { String.valueOf(j).intern(); i++; } System.out.println(i); } }
這時候我們可以看到串池中字元串個數為1871,比默認多了100個。

繼續用上述程式碼做實驗,這會for循環次數為10000,看控制台輸出有什麼變化。

字元串個數為7451並不是11751,因為我們設置了堆記憶體大小為10M,存10000個字元串對象的話堆記憶體發生了MinorGC,將一些無用的對象回收了。

調優:
- 調優主要是對StringTable大小的設置,如果程式中字元串數量非常多,那麼可以將桶個數設置大一些,具體參數為 -XX:StringTableSize = 大小,默認是60013,最小是1009。有這樣一段程式碼:
public class Demo5 { public static void main(String[] args) throws IOException { try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) { String line = null; long start = System.nanoTime(); while (true) { line = reader.readLine(); if (line == null) { break; } line.intern(); } System.out.println("cost:" + (System.nanoTime() - start) / 1000000); } } }
”linux.words”中有480000個字元串,讀取文件然後將字元串放入串池,記錄整個過程消耗時間,以ms為單位並且列印資訊。默認桶個數下消耗時間為0.57秒。

我們設置 -XX:StringTableSize=1009再觀察下消耗時間,變為了9.852秒。所以可根據業務場景來設置桶個數大小。



