线上已修正的内存泄漏整理
前段时间排查出的线上内存泄漏情况,经过一段时间的观察后,确认其中已经解决的记录一下以做参考。
1.最明显的:
日志已经说的很清楚了,由于org.dom4j.DocumentFactory引起的,由于程序员习惯性的将各种bean以单例形式默认注册给Spring IOC,而这次注册的本身就是个单例,这个单例里还有ThreadLocal,导致这个ThreadLocal无法被回收,进一步导致WebAppClassLoader无法被回收,于是heapdump里有三个WebAppClassLoader实例。
2.dbcp2没有提供注销驱动的方法
问题根源是org.apache.commons.dbcp2.BasicDataSource类close()中没有注销JDBC驱动,可能是为了收回线程池复用,但是遇到web容器就坑了。
BasicDataSource's method close() doesn't deregister JDBC driver. This causes permgen memory leaks in web server environments, during context reloads.
常见的解决办法:继承org.apache.commons.dbcp.BasicDataSource 重写close()
例如:
@Override public synchronized void close() throws SQLException { DriverManager.deregisterDriver(DriverManager.getDriver(url)); super.close(); }
3.quartz的bug
<bean id="quartzScheduler" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 增加 <property name="waitForJobsToCompleteOnShutdown" value="true"/>
参考:https://jira.terracotta.org/jira/browse/QTZ-192
4.Quartz + ThreadLocal,现有的应用和定时调度是结合在一起开发部署的,共享了同一个数据源,而线上应用的读写分离实现中使用了包含静态ThreadLocal的单例,虽然这功能quartz用不上,但由于数据源使用的都是配置给Spring管理的同样的方法,同时Quartz是自己维护自己的线程池,Web容器无法对它进行回收导致内存泄漏webappclassloader无法回收,解决办法,Quartz数据源独立,最好应用能独立出去。
5.这个没有确认,因为问题只出现了一次而且已经过了5天。heapdump显示nio引发了内存泄漏,排查相关的日志发现:
rocket提供的issue也并没有什么特别说明:https://github.com/alibaba/RocketMQ/issues/50,由于发送端代码做了重试,也并没有对应用产生影响。网上只找到了些说nio连接如果出现一端因为本地问题私自断开连接会导致内存泄漏,目前也并没有确定是不是这种问题,这个问题还需要跟进。