[
https://issues.jboss.org/browse/DROOLS-498?page=com.atlassian.jira.plugin...
]
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)