项目代码中用到反射,伴随大量的NoSuchFieldException异常,发现cpu飙高,排查后发现跟String.intern有关。 java
在Class中有连个常见的方法: eclipse
Ø public Field getField(String name) this
Ø getMethod(String name, Class<?>... parameterTypes) spa
进入这个方法的实现,发现都会调用searchXXX的方法,已searchFields为例: .net
private Field searchFields(Field[] fields, String name) { String internedName = name.intern(); for (int i = 0; i < fields.length; i++) { if (fields[i].getName() == internedName) { return getReflectionFactory().copyField(fields[i]); } } return null; }
注意这里的name.intern()调用,jdoc它的是说明以下: code
A pool of strings, initially empty, is maintained privately by the class String. ip
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. 内存
简单的说,String.intern()返回String pool中的引用,若是String pool中不存在,则先在String pool中加入一个字符串而后返回该引用。所以,若是s.equals(t) 是true,则 s.intern() == t.intern() 也为true。 字符串
问题来了,因为String pool位于perm区,若是随着String pool愈来愈大,就会引起full gc(只有full gc才会回收perm,另外,perm区的内存在好久好久之前的jdk中是不能被垃圾回收的,jdk1.2之后均可以回收);另外,String pool是hashtable(实际是weakreference)当这个table大了之后,不管是插入仍是查找,都会付出愈来愈大的代价。 get
综合上述状况大量调用String.intern()而且大部分未能在string pool中找到已存在的实例,会引起String pool愈来愈大,进而致使intern方法效率下降,当string pool大到必定程度后,还会引起fgc。所以,慎用String.intern。