user375868
user375868

Reputation: 1378

Heap size not reducing after removing facts from Drool's working memory

I'm creating and inserting fairly light weight Person objects which have one field- age in Drool's working memory. But even after removing facts, heap size is not reducing. Sample code- (using Drools 6.0.0.CR5 from maven)

    long numOfFacts=1000000;

    long heapSize = Runtime.getRuntime().totalMemory();
    System.out.println("Heapsize before insertion: "+heapSize);

    System.out.println("Inserting objects");
    ArrayList<FactHandle> factHandles = new ArrayList<FactHandle>(100);
    for (int i = 0; i < numOfFacts; i++) {
        Person person = new Person();
        person.setAge(randomGenerator.nextInt(100));
        FactHandle factHandle = wkmem.insert(person);
        factHandles.add(factHandle);

    }

    long heapSizeAfter = Runtime.getRuntime().totalMemory();
    System.out.println("Heapsize after insertion: "+heapSizeAfter);


    long endTimeInsert = System.currentTimeMillis();
    long elTime= endTimeInsert-startTimeInsert;
    System.out.println("Time it took to insert " +numOfFacts+" objects :"+elTime+" milliseconds");

    long startTime = System.currentTimeMillis();
    System.out.println("Number of facts: " + wkmem.getFactCount());

    wkmem.fireAllRules();
    long stopTime = System.currentTimeMillis();
    long elapsedTime = stopTime - startTime;
    System.out.println("Time it took for evaluation: " + elapsedTime);
    for(int i=0;i<numOfFacts;i++){
        wkmem.retract(factHandles.get(i));
    }

    long heapSizeAfterRemoval = Runtime.getRuntime().totalMemory();
    System.out.println("Heapsize after removal of facts: "+heapSizeAfterRemoval);

The output of code is-

Heapsize before insertion: 158138368
Inserting objects
Heapsize after insertion: 746717184
Time it took to insert 1000000 objects :5372 milliseconds
Number of facts: 1000000
Time it took for evaluation: 839
Heapsize after removal of facts: 792002560

Why is that heapsize has in fact increased?

Upvotes: 1

Views: 2943

Answers (2)

Steve
Steve

Reputation: 9480

As mentioned in Peter Lawrey's answer, you're not going to to see heap size reduced in the middle of a method. Unless perhaps GC just happens to kick in at that very moment. To test for that, you need to have a long-running application and connect to it with something such as JConsole or use a profiler of some sort.

However, it is worth noting that the way you are retracting is not reliable and will result in memory leaks in some cases. The truth is that in some cases Drools will generate FactHandles internally, so that after retracting all facts associated with your own fact handle references, there may well be more sitting in working memory. If I remember right, these keep hold of references to your facts, which prevents those objects from being garbage collected. Therefore it's a lot safer to just retract all fact handles:

public void retractAll() {
    for (FactHandle handle : ksession.getFactHandles()) {
        retract(handle);
    }
}

... or retract all FactHandles for a filter:

public void retractAll(ObjectFilter filter) {
    for (FactHandle handle : ksession.getFactHandles(filter)) {
        retract(handle);
    }
}

I discovered this the hard way ... my retraction code made the same assumption as yours originally. :)

Upvotes: 3

Peter Lawrey
Peter Lawrey

Reputation: 533660

The heap size always stays the same or increases, until the GC needs to run or decides to run (for concurrent collectors)

Collecting memory is expensive so it only does it when it has to, not when it might.

Why is that heapsize has in fact increased?

Removing objects can do some work which can end up creating temporary objects.

Basically you should only look at memory consumption after a Full GC, anything else is on a least effort basis.

Upvotes: 1

Related Questions