当前位置: 首页 > Java > 正文

JDK7里的String.intern的变化

1 星2 星3 星4 星5 星 (2 次投票, 评分: 5.00, 总分: 5)
Loading ... Loading ...
baidu_share

有一段这样的代码:

1
2
3
4
5
for (int i = 0; i < 10000000; i++) {
    ("bluedavy" + i).intern();
    if(i % 100 == 0)
    Thread.sleep(1);
}

大家可以分别用这段代码在JDK 6里和JDK 7里跑跑看看,会有什么不同。

上面的代码在JDK 7里执行时比JDK 6将会更多的触发Young GC和Full GC,原因请见这段描述:

In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.

简单来说就是在JDK 7里String.intern生成的String不再是在perm gen分配,而是在Java Heap中分配,因此自然上面的这段代码在JDK 7里会产生更为严重的Young GC和Full GC,就像上面这段描述里说的一样,这个变化对于装载了很多类的应用估计还是会有些明显的影响,对反射使用多的其实也会有些影响。

关于这个变化,在Stack Overflow上还有个有趣的case:

1
2
3
4
5
6
7
8
9
10
11
12
class Test
{
 public static void main(String... args)
 {
  String s1="Good";
  s1=s1+"morning";
  System.out.println(s1.intern());
 
  String s2="Goodmorning";
  System.out.println(s1==s2);
 }
}

上面这段代码在目前的JDK 6里和JDK 7里竟然会不同,JDK6里会输出false,而JDK 7会输出true,原因是JDK 6中执行String.intern时需要将此字符串的实例cp到perm并生成一个新的String对象,因此上面的s1和s2的对象地址是不同的,而在JDK 7中,执行String.intern时,则只是在String Pool中记录此字符内容对应的字符串实例。

尽管在比较字符串时,一般都不会用 == 去比较,但还是要知道String.intern的这个变化。

String.intern放进的String Pool是一个固定大小的Hashtable,默认值是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找)。

现在仔细想想,看来当时这个case并不是因为频繁抛异常造成的,而是因为这个case中抛的是NoSuchMethodException,而抛这个异常的原因是因为调用了Class.getMethod找方法没找到,在class.getMethod这方法的实现里会调用name.intern,而很不幸的是这个case里传入的name会根据请求而变,因此导致了String Pool中放入了很多的String,hash冲突严重,链表变长,从而才导致了造成了String.intern过程变得比较耗CPU。

JDK为了解决这个问题,在6u32以及JDK 7的版本里支持了StringTable大小的配置功能,可在启动参数上增加-XX:StringTableSize来设置,具体的信息见:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6962930
不过目前JDK未提供方法来查看StringTable中各桶的链表长度,如果提供这个的话就更好了。

本文固定链接: http://www.chepoo.com/jdk7-string-intern-change.html | IT技术精华网

【上一篇】
【下一篇】

JDK7里的String.intern的变化:等您坐沙发呢!

发表评论