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

Reply via email to