Drools 6.3.0升级后旧ZipKieModule滞留堆内存问题求助
排查Drools 6.3.0 ZipKieModule内存泄漏的实用方向
嘿,这种动态更新规则导致的旧模块内存滞留问题,在Drools 6.x搭配Wildfly的场景里确实挺棘手的。结合你用MAT抓到的6个ZipKieModule实例线索,我给你梳理几个具体的排查方向,你可以一步步验证:
1. 检查KieBase/KieSession的资源未释放
- Drools的
KieBase和KieSession是直接绑定到具体ZipKieModule实例的,如果业务代码里没有显式调用KieSession.dispose(),或者用静态引用持有了KieBase,这些活跃对象会死死拉住旧模块,阻止GC回收。 - 用MAT的**支配树(Dominator Tree)**功能,定位旧
ZipKieModule的引用链,看看是不是被某个未关闭的KieSession或者静态类攥着不放。 - 重点注意:有状态
KieSession如果不手动dispose,会一直占用资源;哪怕是无状态的,频繁创建却不关闭也会累积大量无效引用。
2. 验证KieScanner与KieContainer的生命周期
- 先查
KieScanner的初始化逻辑:如果应用里创建了多个扫描器实例,或者模块更新时没正确清理旧扫描器的引用,旧KieModule可能会被扫描器持有。 - 确认你是不是复用了同一个
KieContainer实例?正确的姿势应该是用同一个容器,让KieScanner自动更新它的模块;如果每次更新都新建KieContainer,旧容器的引用没释放,必然会带着旧模块一起留在堆里。 - 另外,检查是否在应用停止或模块更新时调用了
KieScanner.stop()?虽然Drools 6.3.0的扫描器会自动切换模块,但自定义的扫描逻辑很可能漏了这一步。
3. Wildfly类加载器的引用泄漏
- Wildfly 10的模块化类加载机制下,每个kjar对应一个专属类加载器。如果旧kjar的类加载器被外部对象持有——比如线程上下文类加载器、静态缓存、第三方库的线程局部变量——整个
ZipKieModule都没法被GC回收。 - 用MAT的**线程分析(Thread Analysis)**功能,看看有没有线程的上下文类加载器还指向旧kjar的类加载器;再查有没有静态集合(比如自定义的规则缓存)存着旧kjar里的类实例。
- 划重点:Drools的
KieModule是由类加载器加载的,类加载器活一天,模块实例就别想被回收。
4. 自定义扩展或第三方依赖的隐性引用
- 如果你的应用加了自定义Drools扩展(比如自定义工作项、事件监听器),或者用了第三方库集成Drools,这些组件很可能偷偷持有旧模块的引用。
- 举个例子:你给旧
KieBase注册了自定义AgendaEventListener,模块更新时没移除这个监听器,它就会一直拽着旧KieBase,进而拉住旧ZipKieModule;还有工作项管理器如果没清理旧的工作项定义,也会有同样问题。 - 模块更新时,一定要确保所有关联的监听器、工作项、自定义处理器都被正确注销和清理。
5. 排查Drools 6.3.0的已知Bug
- Drools 6.3.0确实存在一些内存泄漏的已知问题,比如
KieScanner更新时旧模块未被正确解除引用,或者KieBase的内部缓存没清理干净。 - 你可以去Drools的官方问题跟踪系统查一下,有没有类似
KIE-XXXX编号的问题报告,专门针对ZipKieModule的内存泄漏;如果能升级到6.3.0之后的小版本(比如6.3.1、6.4.0),很多这类问题已经被修复了。
6. 检查应用中的静态缓存或单例
- 很多应用会用静态集合缓存Drools相关对象(比如
KieBase、规则实例),如果这些缓存没在模块更新时清理旧条目,就会一直攥着旧ZipKieModule的引用。 - 用MAT的OQL查询快速定位静态引用:执行
SELECT * FROM org.drools.compiler.kie.builder.impl.ZipKieModule z WHERE z != null AND z.getClass().getClassLoader() != currentClassLoader(),就能找出被静态对象持有的旧模块实例。
建议你先从MAT的引用链分析入手,找到最直接的引用来源,再针对性解决问题——毕竟内存泄漏的根源往往藏在某个被忽略的资源释放环节里。
内容的提问来源于stack exchange,提问作者Kim Zeevaarders
相关产品推荐
相关产品推荐

