It appears there is another condition where Drools holds onto memory indefinitely. (See
https://issues.jboss.org/browse/DROOLS-516)
Use case: We have a set of rules designed to detect a heartbeat, then report when/if the
heartbeat stops.
Problem: In the normal case of a constant heartbeat, memory is retained in the JVM, even
though the fact count in working memory is 1.
The following rules produce this problem. I have attached a test project that
demonstrates this problem. 600K events are inserted into the stream, then the test driver
waits. After 10 seconds, the “absence detected” rule fires. Requesting a GC via JMC has
no effect. If you hit a key while the test driver is waiting, a new event will be added,
which will cause the “clear absence alarm” rule to fire. At this point some memory is
freed automatically. Requesting another GC removes all memory and the JVM is back in its
(nearly) new condition.
We consider this a memory leak since the events are gone from working memory and will no
longer be considered in any rule evaluations, but they are still active somewhere in the
JVM.
package org.drools.example.api.kiemodulemodel
import demo.Event
declare Event
@role( event )
@timestamp( timestamp )
end
declare Heartbeat
@role( event )
@timestamp( event.timestamp )
event : Event
end
declare AbsenceDetected
name : String
end
/*
* This rule matches the first event
*
* NOTE: This stream requires the heartbeat event
* to occur at least once before absence will be detected.
*/
rule "detect first heartbeat"
when
$event : Event()
not ( Heartbeat() )
then
delete($event);
insert(new Heartbeat($event));
System.out.println("[DFH] Got event: " + $event.getEventId());
end
/*
* This rule matches every event and stores only the most recent
* as the heartbeat.
*/
rule "keep latest heartbeat"
when
$heartbeat : Heartbeat()
$event : Event()
then
delete($heartbeat);
insert(new Heartbeat($event));
System.out.println("[KLH] Got event: " + $event.getEventId());
delete($event);
end
/*
* This rule detects when a heartbeat stops for 10s
*/
rule "detect absence"
duration(10s)
when
$heartbeat : Heartbeat()
not ( Event() )
not (AbsenceDetected() )
then
delete($heartbeat);
insert(new AbsenceDetected("Absence"));
System.out.println("[DA] Absence detected");
end
/*
* This rule detects when the heartbeat starts again after
* absence has been detected.
*/
rule "clear absence alarm"
when
$heartbeat : Heartbeat()
$absence : AbsenceDetected ()
then
delete($absence);
System.out.println("[CAA] Heartbeat restored");
end