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 <toshiyakobaya...@gmail.com> 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: commits-unsubscr...@kie.apache.org For additional commands, e-mail: commits-h...@kie.apache.org