intern在jdk7的变化

之前的印象都是string pool分配在perm gen内存中的,也通过intern方法验证过perm gen的oom,今天在用jprofiler观察时却发现是heap一直在做gc,直到报heap oom,还以为是测试代码有误,检查了好久猛然想到会不会是jdk7对intern方法有改变呢?参考http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html,原文如下:

Area: HotSpot
Synopsis: 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.
RFE: 6962931

参考这篇文章http://www.tuicool.com/articles/Q73YRf,里面有个案例也很有代表性

String.intern放进的String Pool是一个固定大小的Hashtable,默认值是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找)。 
之前碰到过一个频繁抛异常造成cpu us很高的case: http://bluedavy.me/?p=409 
现在仔细想想,看来当时这个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来设置,不过目前JDK未提供方法来查看StringTable中各桶的链表长度,如果提供这个的话就更好了。

 

猜你喜欢

转载自mingren135.iteye.com/blog/2001905