Java String的intern
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的執行結果:false false
對于這個結果很好理解。在JDK6中,常量池在永久代分配內存,永久代和Java堆的內存是物理隔離的,執行intern方法時,如果常量池不存在該字符串,虛擬機會在常量池中復制該字符串,并返回引用,所以需要謹慎使用intern方法,避免常量池中字符串過多,導致性能變慢,甚至發生PermGen內存溢出。
2、JDK7的執行結果:true false
對于這個結果就有點懵了。在JDK7中,常量池已經在Java堆上分配內存,執行intern方法時,如果常量池已經存在該字符串,則直接返回字符串引用,否則復制該字符串對象的引用到常量池中并返回,所以在JDK7中,可以重新考慮使用intern方法,減少String對象所占的內存空間。
對于變量s1,常量池中沒有 “StringTest” 字符串,s1.intern() 和 s1都是指向Java對象上的String對象。
對于變量s2,常量池中一開始就已經存在 “java” 字符串,所以 s2.intern() 返回常量池中 “java” 字符串的引用。
String.intern()性能
常量池底層使用StringTable數據結構保存字符串引用,實現和HashMap類似,根據字符串的hashcode定位到對應的數組,遍歷鏈表查找字符串,當字符串比較多時,會降低查詢效率。
在JDK6中,由于常量池在PermGen中,受到內存大小的限制,不建議使用該方法。
在JDK7、8中,可以通過-XX:StringTableSize參數StringTable大小,下面通過幾個測試用例看看intern方法的性能
執行一百萬次intern()方法,不同StringTableSize的耗時情況如下:
1、-XX:StringTableSize=1009, 平均耗時23000ms;
2、-XX:StringTableSize=10009, 平均耗時2200ms;
3、-XX:StringTableSize=100009, 平均耗時200ms;
4、默認情況下,平均耗時400ms;
在默認StringTableSize下,執行不同次intern()方法的耗時情況如下:
1、一萬次,平均耗時5ms;
2、十萬次,平均耗時25ms;
3、五十萬次,平均耗時130ms;
4、一百萬次,平均耗時400ms;
5、五百萬次,平均耗時5000ms;
6、一千萬次,平均耗時15000ms;
從這些測試數據可以看出,盡管在Java 7以上對intern()做了細致的優化,但其耗時仍然很顯著,如果無限制的使用intern()方法,將導致系統性能下降,不過可以將有限值的字符串放入常量池,提高內存利用率,所以intern()方法是一把雙刃劍。
轉載于:https://blog.51cto.com/12666319/2114724
總結
以上是生活随笔為你收集整理的Java String的intern的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理解Python中的类对象、实例对象、属
- 下一篇: Kotlin 喧嚣过后,谈谈 Java