一次ClassLoader引发的应用无响应
事情是这样的
在一个平平无奇的上午,收到同事反馈,某个应用突然特别卡,响应时间非常长,于是让他先保存应用运行的快照,用jstack命令导出三次线程信息,每次间隔3到5秒。
拿到线程信息后,用TDA工具打开,话不多话,直接上图
其它两个线程信息也是如此,略去不表。可以看到,有554个线程在等着拿org.eclipse.jetty.webapp.WebAppClassLoader
这把锁,WebAppClassLoader
是应用中间件jetty
用来加载类的。
分析
第一个为什么
原因
•项目使用的Controller层
由于历史原因,不是使用spring管理的单例,而是每个请求过来,通过Class.forName
反射生成的•项目大量使用Hibernate和HQL语言,会将查询结果转换成pojo类,会大量调用hibernate的ReflectHelper.classForName
反射生成对象实例。
•jetty7.6
的WebappClassLoader
是直接在loadClass
方法上加synchonized
第二个为什么
原因
•如果不加锁,那同一个ClassLoader有可能同时加载多次同名Class,产生多个Class实例,这样会让程序运行产生不可预知的结果。
第三个为什么
•为什么加锁要在loadClass
上加锁,一类不锁它不香吗
原因
•一类一锁是香,只是jdk的开发人员没想到你们能这么去用反射,所以之前就没这么实现,在jdk1.7
的ClassLoader
类才实现了一类一锁
•然后jetty9
的WebappClassLoader
实现了按类名加锁
第四个为什么
•为什么Hibernate的ReflectHelper.classForName
用了这么多反射
原因
•人谁无过•不过hibernate在5.XX的版本进行了优化
最后的解决方案
•由于升级jetty或者hibernate的代价较大,临时重新了jetty7.6的ClassLoader和Hibernate的ReflectHelper
.•原因都找出来了,其他项目组可以根据自己的具体情况选择不同的解决方案。•晚安!
本文分享自微信公众号 - 程序员阿水(gh_124d28263603)。
如有侵权,请联系 [email protected] 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。