将对象插入基于Timer的规则会话时,Drools KieSession会导致内存泄漏

时间:2016-10-31 11:49:58

标签: java multithreading memory-leaks timer drools

我们想用Drools来做延迟工作。所以,我使用timer(int:5s)来做到这一点。但是,在我向KieSession插入一个事实对象之后,KieSession将启动一个单独的“Thread-XX”来处理这个延迟作业,但是这个线程永远不会结束,尽管规则已经过了5s后才执行。

因此,如果我插入一个大量的事实对象,例如100000个对象,这个KieSession中将有100000个线程,内存将增加到大约500MB并且它永远不会下降。插入越多,消耗的内存就越多。

我认为如果对象已被评估并执行规则,Drools应该关闭这些线程,因为它们没用。

是否有一些选项可以在执行后使这些定时器线程关闭?我知道drl文件中的drools.halt(),但它会停止整个会话而不是这个KieSession中的每个线程。

以下是我的代码:

1.main class

        KieServices ks = KieServices.Factory.get();
        final KieContainer kContainer = ks.getKieClasspathContainer();
        final KieSessionConfiguration ksconf = ks.newKieSessionConfiguration();
        ksconf.setOption(TimedRuleExectionOption.YES);
        final KieSession kSession = kContainer.newKieSession("ksession-rules", ksconf);

        for (int i = 0; i < 100000; i++) {
            Thread t1 = new Thread(new Runnable() {
                public void run() {
                    Message message = new Message();
                    message.setStatus(Message.HELLO);
                    kSession.insert(message);
                    kSession.fireUntilHalt();
                }
            });

            t1.start();
        }
  1. drl file

        dialect "mvel"
        rule "Hello World"
        timer(int:10s)
           when
              m : Message(m.status == Message.HELLO)
           then
              System.out.println( "no hello"+m.message );
        end
    
  2. 上面的代码是分享KieSession。我也尝试每个事实使用一个KieSession,然后停止并处理它。但是,100000 KieSession同时驻留在内存中会导致6.7GB的内存使用量。这也是不可接受的。

    那么,任何人都可以帮助我吗?

    实际上,我的业务逻辑是在5分钟内检查控制点和反馈点是否相同,否则发出警报。并且同时会有大约100000个请求。那么,Drools还有其他更好的方法来实现这个案例吗?

    谢谢,

2 个答案:

答案 0 :(得分:0)

上面代码中的问题会将kSession.fireUntilHalt();称为100000次,这不符合文档准则,不是最佳做法,如果我遵循您的代码意图,则在语义上似乎不正确。

如果你想使用Active mode (fireUntilHalt),你可以在一个单独的主题中调用kSession.fireUntilHalt();,一次开始;然后,你插入事实。

否则,相应于您的代码而不一定需要另一个线程,您可以使用fireAllRules()使用被动模式,但架构选择取决于应用程序要求。

Drools文档“规则执行模式”中详细介绍了一个全面的解释,我在上面也链接了有关活动模式的内容(fireUntilHalt)

我假设Drools版本6.x基于API使用,但我可能错了。

编辑以下评论“未完成的主题”不是用户代码创建的那个,而且“我也称为kSession.retract(item)睡了1分钟后。但是记忆仍在那里,没有下降。

我真的很有兴趣听取OP的评论,但坦率地说即使进行进一步的调查也不可能强调这样的说法。正确使用API​​准则,不会产生数千个线程:

enter image description here

可以看出,线程数没有显示任何相关性 - 请注意运行测试当然,JUnit运行程序也需要一些线程。

....并且跟随“我在睡眠1分钟后也调用了kSession.retract(item)。但内存仍然存在,没有下拉。”内存执行INDEED下降:

enter image description here

当然,在声明一百万个事实时,内存占用依赖于有状态会话涉及多个参数,但即使遵循OP的断言记忆也没有显示任何有意义的东西。所以我无法重现任何相关的内存泄漏。

如果您仍然认为存在问题或内存泄漏,请使用重现突出显示问题的JIRA问题单,以便对其进行适当调查,谢谢。

答案 1 :(得分:0)

我认为你不应该使用Drools来安排大量的TimerTasks。您可以将Timer设置为全局,并根据需要调用其计划方法。

很明显,简单的计时器属性无法处理java.util.Timer和TimerTask的API可能出现的各种情况。其主要目的是涵盖在条件普遍存在的情况下重复执行某些事情的简单方案。此外,计时器属性就在那里,所以Drools营销可以宣称“你可以在Drools中完成所有工作,不需要知道(很多)Java”。呸。