记Introspector.getBeanInfo()引起的Full GC
背景
开发环境压力测试,100并发,FullGC频繁,一个转换工具类BeanWithMapHandlerUtil
//把JavaBean转化为map public static Map<String, Object> beanToMap(Object bean) throws BaseAppException { Map<String, Object> map = new HashMap<>(); //获取JavaBean的描述器 BeanUtils.describe() <String, String> try { BeanInfo b = Introspector.getBeanInfo(bean.getClass(), Object.class); //获取属性描述器 PropertyDescriptor[] pds = b.getPropertyDescriptors(); //对属性迭代 for (PropertyDescriptor pd : pds) { //属性名称 String propertyName = pd.getName(); //属性值,用getter方法获取 Method m = pd.getReadMethod(); //用对象执行getter方法获得属性值 Object properValue = m.invoke(bean); // 判断是否有 list if (properValue instanceof java.util.List) { List list = (List) properValue; if (CollectionUtils.isNotEmpty(list)) { Class childClass = list.get(0).getClass(); if (isCommonDataType(childClass) || isWrapClass(childClass)) { map.put(propertyName, list); } else { List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>(); Object obj; for (int i = 0; i < list.size(); i++) { obj = list.get(i); // list里是map或String,不会存在list里直接是list的 Field[] fieldChilds = obj.getClass().getDeclaredFields(); Map<String, Object> resultChild = new HashMap<String, Object>(); for (Field field : fieldChilds) { // 重置属性可见(而且一般属性都是私有的),否则操作无效 boolean accessible2 = field.isAccessible(); if (!accessible2) { field.setAccessible(true); } // 获取属性名称及值存入Map String key = field.getName(); Object objVal = field.get(obj); if (null != objVal && !"".equals(objVal)) { resultChild.put(key, field.get(obj)); } } mapList.add(resultChild); } map.put(propertyName, mapList); } } } else { //把属性名-属性值 存到Map中 if (null != properValue && !"".equals(properValue)) { map.put(propertyName, properValue); } } } } catch (IllegalAccessException e) { throw new BaseAppException("beanToMap IllegalAccessException {}", e); } catch (IntrospectionException e) { throw new BaseAppException("beanToMap IntrospectionException {}", e); } catch (InvocationTargetException e) { throw new BaseAppException("beanToMap InvocationTargetException {}", e); } return map; }
通过thread -n 10 查看线程堆栈信息,线程处在阻塞状态
原因
"http-nio-8080-exec-44" Id=499 cpuUsage=3% BLOCKED on java.lang.Object@53793dcd owned by "http-nio-8080-exec-185" Id=640 at java.lang.ClassLoader.loadClass(ClassLoader.java:404) - blocked on java.lang.Object@53793dcd at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:348) at com.sun.beans.finder.ClassFinder.findClass(ClassFinder.java:103) at java.beans.Introspector.findCustomizerClass(Introspector.java:1301) at java.beans.Introspector.getTargetBeanDescriptor(Introspector.java:1295) at java.beans.Introspector.getBeanInfo(Introspector.java:425) at java.beans.Introspector.getBeanInfo(Introspector.java:262) at java.beans.Introspector.getBeanInfo(Introspector.java:224)
BeanInfo b = Introspector.getBeanInfo(bean.getClass(), Object.class);
可以看到java.lang.ClassLoader#loadClass(java.lang.String, boolean)中有一把synchronized锁,请求DTO转化成Map,并行变串行
解决方案
Map<String, Object> reqMa = JsonUtil.json2Map(JsonUtil.object2Json(bean));
Object转Map换成JsonUtil工具类,验证如下:
public static void main(String[] args) { RestInvocationDto req = new RestInvocationDto(); req.setServer("test"); req.setReqParams("test"); req.setConfigServerKey("test"); req.setBusinessUrl("test"); Thread threadA = new Thread(new Runnable() { @SneakyThrows @Override public void run() { Long begin = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) { Map<String, Object> reqMap = BeanWithMapHandlerUtil.beanToMap(req); } System.out.println("ThreadA costs " + (System.currentTimeMillis() - begin) + "ms"); } }); Thread threadB = new Thread(new Runnable() { @SneakyThrows @Override public void run() { Long begin = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) { JsonUtil.json2Map(JsonUtil.object2Json(req)); } System.out.println("ThreadB costs " + (System.currentTimeMillis() - begin) + "ms"); } }); threadA.start(); threadB.start(); }
ThreadB costs 2321ms
ThreadA costs 8312ms
不积跬步,无以至千里;不积小流,无以成江海