Java 从Drool的工作内存中删除事实后堆大小没有减小

Java 从Drool的工作内存中删除事实后堆大小没有减小,java,memory-management,memory-leaks,heap,drools,Java,Memory Management,Memory Leaks,Heap,Drools,我正在创建并插入相当轻的人物对象,这些对象在Drool的工作记忆中只有一个字段年龄。但即使在删除事实之后,堆大小也没有减少。示例代码-使用maven的Drools 6.0.0.CR5 long numOfFacts=1000000; long heapSize = Runtime.getRuntime().totalMemory(); System.out.println("Heapsize before insertion: "+heapSize); Sys

我正在创建并插入相当轻的人物对象,这些对象在Drool的工作记忆中只有一个字段年龄。但即使在删除事实之后,堆大小也没有减少。示例代码-使用maven的Drools 6.0.0.CR5

    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);

为什么治疗的次数实际上增加了

堆大小始终保持不变或增加,直到GC需要运行或决定为并发收集器运行

收集内存是昂贵的,所以它只在必要的时候做,而不是在可能的时候做

为什么治疗的次数实际上增加了

删除对象可以完成一些工作,最终可能会创建临时对象


基本上,您应该只在完全GC之后查看内存消耗,其他任何操作都是以最少的工作量为基础的。

堆大小始终保持不变或增加,直到GC需要运行或决定为并发收集器运行为止

收集内存是昂贵的,所以它只在必要的时候做,而不是在可能的时候做

为什么治疗的次数实际上增加了

删除对象可以完成一些工作,最终可能会创建临时对象


基本上,你应该只在一个完整的GC之后查看内存消耗,其他任何事情都是在最不费力的基础上。

正如Peter Lawrey的回答中所提到的,在一个方法的中间你不会看到堆大小减少了。除非GC恰好在那一刻启动。为了测试这一点,您需要有一个长期运行的应用程序,并使用诸如JConsole之类的东西连接到它,或者使用某种探查器

但是,值得注意的是,收回的方式不可靠,在某些情况下会导致内存泄漏。事实是,在某些情况下,Drools会在内部生成FactHandles,因此在收回与您自己的事实句柄引用相关的所有事实之后,工作内存中可能会有更多的内容。如果我没记错的话,这些文件保留了对您的事实的引用,从而防止这些对象被垃圾收集。因此,收回所有事实句柄要安全得多:

public void retractAll() {
    for (FactHandle handle : ksession.getFactHandles()) {
        retract(handle);
    }
}
。。。或收回过滤器的所有FactHandle:

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

我发现这很难。。。我的撤回代码与你最初的假设相同: 但是,值得注意的是,收回的方式不可靠,在某些情况下会导致内存泄漏。事实是,在某些情况下,Drools会在内部生成FactHandles,因此在收回与您自己的事实句柄引用相关的所有事实之后,工作内存中可能会有更多的内容。如果我没记错的话,这些文件保留了对您的事实的引用,从而防止这些对象被垃圾收集。因此,收回所有事实句柄要安全得多:

public void retractAll() {
    for (FactHandle handle : ksession.getFactHandles()) {
        retract(handle);
    }
}
。。。或收回过滤器的所有FactHandle:

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

我发现这很难。。。我的撤回代码与你最初的假设相同:

也谢谢你史蒂夫-在我找到这篇文章之前,这是我心中的一根刺…也谢谢史蒂夫-在我找到这篇文章之前,这是我心中的一根刺。。。。