String.intern()引发的性能问题

项目代码中用到反射,伴随大量的NoSuchFieldException异常,发现cpu飙高,排查后发现跟String.intern有关。

Class中有连个常见的方法:

Ø public Field getField(String name)

Ø getMethod(String name, Class<?>... parameterTypes)

进入这个方法的实现,发现都会调用searchXXX的方法,已searchFields为例:

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它的是说明如下:

A pool of strings, initially empty, is maintained privately by the class String.

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 poolhashtable(实际是weakreference)当这个table大了以后,无论是插入还是查找,都会付出越来越大的代价。

综合上述情况大量调用String.intern()并且大部分未能在string pool中找到已存在的实例,会引发String pool越来越大,进而导致intern方法效率降低,当string pool大到一定程度后,还会引发fgc。因此,慎用String.intern。

 

你可能感兴趣的:(垃圾回收,fullgc,StringPool,String.intern)