[jboss-jira] [JBoss JIRA] (DROOLS-498) Memory leak in stateful session after retracting facts
Kent Anderson (JIRA)
issues at jboss.org
Tue Jul 15 16:06:30 EDT 2014
[ https://issues.jboss.org/browse/DROOLS-498?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12985354#comment-12985354 ]
Kent Anderson edited comment on DROOLS-498 at 7/15/14 4:04 PM:
---------------------------------------------------------------
Thanks for checking back on this, Davide.
My workstation is running Oracle Java 1.7.0_60 on MacOS. Our test environment is Linux: CentOS 6 with Oracle Java 1.7.0_25. The problem shows up in both environments.
Here is the listing of the test case...
{code}
@Test
public void testDurationMemoryLeak() throws Exception {
String drl =
"import org.drools.compiler.StockTick;\n " +
"declare StockTick\n"+
" @role( event )\n"+
" @timestamp( time )\n"+
"end\n"+
"rule \"announce DROO\"\n"+
" no-loop\n"+
"when\n"+
" $droo : StockTick( company == \"DROO\" )\n"+
"then\n"+
" System.out.println(\"Received the DROO\");\n"+
"end\n"+
"rule \"delay DROO\"\n"+
" no-loop\n"+
" duration(2s)\n"+
"when\n"+
" $droo : StockTick( company == \"DROO\" )\n"+
"then\n"+
" System.out.println(\"forwarding the DROO\");\n"+
" delete($droo);\n"+
"end\n"+
"rule \"cancel RAISE\"\n"+
" no-loop\n"+
"when\n"+
" $oord : StockTick( company == \"OORD\" )\n"+
" $droo : StockTick( company == \"DROO\" )\n"+
"then\n"+
" System.out.println(\"Canceling the DROO due to a OORD\");\n"+
" delete($droo);\n"+
" delete($oord);\n"+
"end";
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newByteArrayResource(drl.getBytes()), ResourceType.DRL);
if ( kbuilder.hasErrors() ) {
fail( kbuilder.getErrors().toString() );
}
KieBaseConfiguration baseConfig = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
baseConfig.setOption( EventProcessingOption.STREAM );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( baseConfig );
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
KieSession ksession = kbase.newKieSession();
StatefulKnowledgeSessionImpl internalSession = (StatefulKnowledgeSessionImpl) ksession;
assertEquals("FactCount should be 0[1]", 0, ksession.getFactCount());
FactHandle hRaise = ksession.insert(new StockTick(0, "DROO", 1.00));
ksession.fireAllRules();
assertEquals("FactCount should be 1[2]", 1, ksession.getFactCount());
Thread.sleep(500);
ksession.insert(new StockTick(1, "OORD", 1.00));
ksession.fireAllRules();
assertEquals("FactCount should be 0[3]", 0, ksession.getFactCount());
Thread.sleep(500);
hRaise = ksession.insert(new StockTick(2, "DROO", 1.00));
ksession.fireAllRules();
assertEquals("FactCount should be 1[4]", 1, ksession.getFactCount());
Thread.sleep(2100);
ksession.fireAllRules();
assertEquals("FactCount should be 0[5]", 0, ksession.getFactCount());
assertTrue("Object should no longer exist",
null == internalSession.getObjectStore().getObjectForHandle(hRaise));
((DefaultAgenda)ksession.getAgenda()).getGarbageCollector().forceGcUnlinkedRules();
/*
* Uncomment the following while loop to hold the JVM open so you can
* grab a heap dump using JVisualVM. Execute the following OQL query
* to see that the StockTick(2, "DROO", 1.00) object that was the final
* event inserted above is still referenced in memory. It should not
* be.
*/
while(true){
Thread.sleep(10000);
}
// Final assert needed: need to verify that the StockTock(2, "DROO", 1.00)
// object is no longer referenced in any of the internal Drools data
// structures. Not sure how to do this using the Drools api.
}
{code}
was (Author: kanderson.psware):
Thanks for checking back on this, Davide.
Here is the listing of the test case...
{code}
@Test
public void testDurationMemoryLeak() throws Exception {
String drl =
"import org.drools.compiler.StockTick;\n " +
"declare StockTick\n"+
" @role( event )\n"+
" @timestamp( time )\n"+
"end\n"+
"rule \"announce DROO\"\n"+
" no-loop\n"+
"when\n"+
" $droo : StockTick( company == \"DROO\" )\n"+
"then\n"+
" System.out.println(\"Received the DROO\");\n"+
"end\n"+
"rule \"delay DROO\"\n"+
" no-loop\n"+
" duration(2s)\n"+
"when\n"+
" $droo : StockTick( company == \"DROO\" )\n"+
"then\n"+
" System.out.println(\"forwarding the DROO\");\n"+
" delete($droo);\n"+
"end\n"+
"rule \"cancel RAISE\"\n"+
" no-loop\n"+
"when\n"+
" $oord : StockTick( company == \"OORD\" )\n"+
" $droo : StockTick( company == \"DROO\" )\n"+
"then\n"+
" System.out.println(\"Canceling the DROO due to a OORD\");\n"+
" delete($droo);\n"+
" delete($oord);\n"+
"end";
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newByteArrayResource(drl.getBytes()), ResourceType.DRL);
if ( kbuilder.hasErrors() ) {
fail( kbuilder.getErrors().toString() );
}
KieBaseConfiguration baseConfig = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
baseConfig.setOption( EventProcessingOption.STREAM );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( baseConfig );
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
KieSession ksession = kbase.newKieSession();
StatefulKnowledgeSessionImpl internalSession = (StatefulKnowledgeSessionImpl) ksession;
assertEquals("FactCount should be 0[1]", 0, ksession.getFactCount());
FactHandle hRaise = ksession.insert(new StockTick(0, "DROO", 1.00));
ksession.fireAllRules();
assertEquals("FactCount should be 1[2]", 1, ksession.getFactCount());
Thread.sleep(500);
ksession.insert(new StockTick(1, "OORD", 1.00));
ksession.fireAllRules();
assertEquals("FactCount should be 0[3]", 0, ksession.getFactCount());
Thread.sleep(500);
hRaise = ksession.insert(new StockTick(2, "DROO", 1.00));
ksession.fireAllRules();
assertEquals("FactCount should be 1[4]", 1, ksession.getFactCount());
Thread.sleep(2100);
ksession.fireAllRules();
assertEquals("FactCount should be 0[5]", 0, ksession.getFactCount());
assertTrue("Object should no longer exist",
null == internalSession.getObjectStore().getObjectForHandle(hRaise));
((DefaultAgenda)ksession.getAgenda()).getGarbageCollector().forceGcUnlinkedRules();
/*
* Uncomment the following while loop to hold the JVM open so you can
* grab a heap dump using JVisualVM. Execute the following OQL query
* to see that the StockTick(2, "DROO", 1.00) object that was the final
* event inserted above is still referenced in memory. It should not
* be.
*/
while(true){
Thread.sleep(10000);
}
// Final assert needed: need to verify that the StockTock(2, "DROO", 1.00)
// object is no longer referenced in any of the internal Drools data
// structures. Not sure how to do this using the Drools api.
}
{code}
> Memory leak in stateful session after retracting facts
> ------------------------------------------------------
>
> Key: DROOLS-498
> URL: https://issues.jboss.org/browse/DROOLS-498
> Project: Drools
> Issue Type: Bug
> Security Level: Public(Everyone can see)
> Affects Versions: 6.0.1.Final
> Reporter: Vitaly Lomov
> Assignee: Mario Fusco
> Priority: Critical
> Attachments: gcRoot.png, memory-leak2.zip, screenshot1.png
>
>
> After adding many simple facts into the stateful session and then removing them, the factHandles for the removed facts are still referenced by the session. Eventually getting "java.lang.OutOfMemoryError: GC overhead limit exceeded" with the stack trace (sometimes) similar to DROOLS-411.
> Someone on StackOverflow suggested iterating through whatever factHandles remain after deletion and delete those, but I get no factHandles (correct, since I removed all facts).
> See screenshot for objects in memory _after_ deleting all facts.
--
This message was sent by Atlassian JIRA
(v6.2.6#6264)
More information about the jboss-jira
mailing list