This is an automated email from the ASF dual-hosted git repository.
tkobayas pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 2678a94d84 [incubator-kie-drools-6361] Dormant matches memory leak
(#6364) (#6373)
2678a94d84 is described below
commit 2678a94d844299c34ea88755852d91b6dab1a10b
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Thu Jun 12 19:12:12 2025 +0900
[incubator-kie-drools-6361] Dormant matches memory leak (#6364) (#6373)
* [incubator-kie-drools-6361] Dormant matches memory leak
- Test only
* add join rule test
* - tmp fix for dormant
* do not delete orphaned tuple
* - minor test clean up
* typo
* disable memory leak tests by default
---
.../org/drools/core/reteoo/AlphaTerminalNode.java | 3 +
.../org/drools/mvel/compiler/MemoryLeakTest.java | 103 +++++++++++++++++++++
2 files changed, 106 insertions(+)
diff --git
a/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
b/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
index 66b53817c0..6cae9ceabf 100644
--- a/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
+++ b/drools-core/src/main/java/org/drools/core/reteoo/AlphaTerminalNode.java
@@ -96,6 +96,9 @@ public class AlphaTerminalNode extends LeftInputAdapterNode {
ActivationsManager activationsManager =
reteEvaluator.getActivationsManager();
leftTuple.setPropagationContext( context );
TerminalNode rtn = (TerminalNode) leftTuple.getSink();
+ if (((InternalMatch)leftTuple).isMatched()) {
+ leftTuple.setStagedType(Tuple.DELETE);
+ }
PhreakRuleTerminalNode.doLeftDelete( activationsManager,
getRuleAgendaItem( reteEvaluator, activationsManager, rtn, false
).getRuleExecutor(), (RuleTerminalNodeLeftTuple) leftTuple );
}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/MemoryLeakTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/MemoryLeakTest.java
index 3668ec9836..e1bae24188 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/MemoryLeakTest.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/MemoryLeakTest.java
@@ -313,4 +313,107 @@ public class MemoryLeakTest {
}
return childObjects;
}
+
+ @Disabled("disabled by default as this could be unstable")
+ @ParameterizedTest(name = "KieBase type={0}")
+ @MethodSource("parameters")
+ @Timeout(60)
+ public void testLeakWithMatchAndDelete(KieBaseTestConfiguration
kieBaseTestConfiguration) {
+ String drl =
+ "import " + Person.class.getCanonicalName() + "\n" +
+ "rule R when\n" +
+ " $p : Person(name == \"Mario\")\n" +
+ "then\n" +
+ "end\n";
+
+ KieBase kBase = KieBaseUtil.getKieBaseFromKieModuleFromDrl("test",
kieBaseTestConfiguration, drl);
+
+ try (KieSession ksession = kBase.newKieSession()) {
+ String text24kb = "A".repeat(24 * 1024);
+
+ System.gc();
+ long baseMemory = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
+
+ for (int i = 0; i < 10000; i++) {
+ Person person = new Person("Mario", i);
+ person.setLikes(text24kb + i); // make sure that different
String instances are created
+ FactHandle factHandle = ksession.insert(person);
+ int fired = ksession.fireAllRules();
+ assertThat(fired).isEqualTo(1);
+
+ ksession.delete(factHandle);
+ ksession.fireAllRules();
+
+ if (i % 1000 == 0) {
+ System.gc();
+ long usedMemory = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
+ System.out.println("Used memory: " + usedMemory);
+ }
+ }
+ System.out.println("------------------");
+ // Allow some memory for the processing overhead
+ // The acceptableMemoryOverhead may not be a critical threshold.
If the test fails, you may consider increasing it if it's not a memory leak.
+ long acceptableMemoryOverhead = 10 * 1024 * 1024; // 10 MB
+ System.gc();
+ long usedMemory = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
+ System.out.println("Base memory: " + baseMemory);
+ System.out.println("User memory: " + usedMemory);
+ assertThat(usedMemory).isLessThan(baseMemory +
acceptableMemoryOverhead);
+ }
+ }
+
+ @Disabled("disabled by default as this could be unstable")
+ @ParameterizedTest(name = "KieBase type={0}")
+ @MethodSource("parameters")
+ @Timeout(60)
+ public void testLeakWithJoinMatchAndDelete(KieBaseTestConfiguration
kieBaseTestConfiguration) {
+ String drl =
+ "import " + Person.class.getCanonicalName() + "\n" +
+ "import " + Cheese.class.getCanonicalName() + "\n" +
+ "rule R when\n" +
+ " $p : Person(name == \"Mario\")\n" +
+ " $c : Cheese(type == \"stilton\")\n" +
+ "then\n" +
+ "end\n";
+
+ KieBase kBase = KieBaseUtil.getKieBaseFromKieModuleFromDrl("test",
kieBaseTestConfiguration, drl);
+
+ try (KieSession ksession = kBase.newKieSession()) {
+ String text24kb = "A".repeat(24 * 1024);
+
+ System.gc();
+ long baseMemory = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
+
+ for (int i = 0; i < 10000; i++) {
+ Person person = new Person("Mario", i);
+ person.setLikes(text24kb + i); // make sure that different
String instances are created
+ FactHandle factHandlePerson = ksession.insert(person);
+
+ Cheese cheese = new Cheese("stilton");
+ FactHandle factHandleCheese = ksession.insert(cheese);
+
+ int fired = ksession.fireAllRules();
+ assertThat(fired).isEqualTo(1);
+
+ ksession.delete(factHandlePerson);
+ ksession.delete(factHandleCheese);
+ ksession.fireAllRules();
+
+ if (i % 1000 == 0) {
+ System.gc();
+ long usedMemory = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
+ System.out.println("Used memory: " + usedMemory);
+ }
+ }
+ System.out.println("------------------");
+ // Allow some memory for the processing overhead
+ // The acceptableMemoryOverhead may not be a critical threshold.
If the test fails, you may consider increasing it if it's not a memory leak.
+ long acceptableMemoryOverhead = 10 * 1024 * 1024; // 10 MB
+ System.gc();
+ long usedMemory = Runtime.getRuntime().totalMemory() -
Runtime.getRuntime().freeMemory();
+ System.out.println("Base memory: " + baseMemory);
+ System.out.println("User memory: " + usedMemory);
+ assertThat(usedMemory).isLessThan(baseMemory +
acceptableMemoryOverhead);
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]