Java String#intern() 内存模型详解教程
大家知道,Java中string.intern()方法调用会先去字符串常量池中查找相应的字符串,如果字符串不存在,就会在字符串常量池中创建该字符串然后再返回。
字符串常量池是一个固定大小的HashMap,桶的数量默认是1009, 从Java7u40开始,该默认值增大到60013。在Java6当中,字符串常量池是放在Perm空间的,从Java7开始,字符串常量池被移到 Heap空间。下面,我们通过测试程序来窥探字符串常量池在Java6,Java7两个不同版本底下的内存分配情况。
测试程序
<table width="620" cellspacing="1" cellpadding="1" border="0" align="center" style="background:#FB7"> <tbody> <tr> <td width="464" height="27" bgcolor="#FFE7CE"> 代码如下</td> <td width="109" bgcolor="#FFE7CE" align="center" onclick="doCopy('copy7252')" style="cursor:pointer;">复制代码</td> </tr> <tr> <td valign="top" height="auto" bgcolor="#FFFFFF" id="copy7252" class="copyclass" style="padding:10px;" colspan="2">public class StringPoolTest {public void testStringPoolWithLongString(){
long i=0;
while(true){
String longString = "This is a very long string, very very long string to test the gc behavior of the string constant pool" i;
longString.intern();
i ;
}
}
public static void main(String[] args){
StringPoolTest stringPoolTest = new StringPoolTest();
stringPoolTest.testStringPoolWithLongString();
}
}</td> </tr> </tbody> </table>
测试程序很简单,一个死循环,循环里面通过递增变量i制造唯一的字符串,然后用main函数启动程序。
Java 6
我们使用版本Jdk1.6.0_29来跑该程序,打开Java VisualVM监控,可以看到,Perm区不断发生GC,由此的出结论,虽然字符串常量池放在Perm空间,但当Perm空间接近满的时候,JVM会将字符串常量池中的无用字符串回收掉。
<center></center>
Java 7
下面,我们切换到Jdk1.7.0_67重跑该程序,可以看到Perm区内存分配曲线很平滑,没有出现内存分配的现象。
<center></center>
但在Heap空间,新的对象不断产生,然后不断触发GC
<center></center>
结论
由于Perm区大小是有限的,通常只有几十MB,所以不推荐在Java6下广泛使用String.intern(),这篇文章string-intern-in-java-6-7-8的性能测试表明,在Java6底下大量使用intern()会导致应用性能的显著下降,还有可能产生OOM错误。但从Java7开始,字符串常量池被移到了 Heap空间,Heap空间的大小只受制于机器的真实内存大小,因此,在Java7下使用String.intern()能更有效地减少重复String 对象对内存的占用。
您可能感兴趣的文章:
Java String#intern() 内存模型详解教程
java中 String类常量池
Java中的同一性和等同性
java中”==”和”Equal”的区别
Python is与==的对比以及字符串驻留机制
详解Java的String/StringBuffer/StringBuilder异同
php怎么传给java
Java自动内存管理详解
java后端如何调python接口
go 获取函数地址_Go语言基础--接口浅析