項目代碼中用到反射,伴隨大量的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。