Optaplanner 的内存泄漏问题

Memory leak issue with Optaplanner

我有一个课程安排问题,其中包含用于分数计算的约束流。 在解决分配的 堆时,堆不断增加 ,因此几个小时后它甚至超过 8GB,我得到 java.lang.OutOfMemoryError: Java heap space。 如 optaplanner 文档中所述,堆大小在求解器阶段应保持不变。 我需要有关此类行为可能是什么问题以及如何调试的建议

中提供的 reproducer 将重现此行为。 Collectors.toList() 的约束似乎是我项目中导致泄漏的唯一约束。

我做了一些profiling: 占用增加内存的分配对象类型

org.drools.core.util.index.TupleList

线程栈如下:

SwingWorker-pool-1-thread-3
  at org.drools.core.reteoo.BaseLeftTuple.get(I)Lorg/drools/core/common/InternalFactHandle; (BaseLeftTuple.java:406)
  at org.drools.modelcompiler.constraints.BindingEvaluator.getArgument(Lorg/drools/core/common/InternalFactHandle;Lorg/drools/core/common/InternalWorkingMemory;Lorg/drools/core/rule/Declaration;Lorg/drools/core/spi/Tuple;)Ljava/lang/Object; (BindingEvaluator.java:59)
  at org.drools.modelcompiler.constraints.ConstraintEvaluator$InnerEvaluator.getArgument(Lorg/drools/core/common/InternalFactHandle;Lorg/drools/core/common/InternalWorkingMemory;Lorg/drools/core/rule/Declaration;Lorg/drools/core/spi/Tuple;)Ljava/lang/Object; (ConstraintEvaluator.java:234)
  at org.drools.modelcompiler.constraints.ConstraintEvaluator$InnerEvaluator$_2.evaluate(Lorg/drools/core/common/InternalFactHandle;Lorg/drools/core/spi/Tuple;Lorg/drools/core/common/InternalWorkingMemory;)Z (ConstraintEvaluator.java:283)
  at org.drools.modelcompiler.constraints.ConstraintEvaluator.evaluate(Lorg/drools/core/common/InternalFactHandle;Lorg/drools/core/spi/Tuple;Lorg/drools/core/common/InternalWorkingMemory;)Z (ConstraintEvaluator.java:117)
  at org.drools.modelcompiler.constraints.LambdaConstraint.isAllowedCachedRight(Lorg/drools/core/spi/Tuple;Lorg/drools/core/rule/ContextEntry;)Z (LambdaConstraint.java:160)
  at org.drools.core.common.TripleBetaConstraints.isAllowedCachedRight([Lorg/drools/core/rule/ContextEntry;Lorg/drools/core/spi/Tuple;)Z (TripleBetaConstraints.java:123)
  at org.drools.core.phreak.PhreakJoinNode.doRightUpdatesProcessChildren(Lorg/drools/core/reteoo/LeftTuple;Lorg/drools/core/reteoo/LeftTuple;Lorg/drools/core/reteoo/RightTuple;Lorg/drools/core/common/TupleSets;[Lorg/drools/core/rule/ContextEntry;Lorg/drools/core/common/BetaConstraints;Lorg/drools/core/reteoo/LeftTupleSink;Lorg/drools/core/util/FastIterator;Lorg/drools/core/common/TupleSets;)Lorg/drools/core/reteoo/LeftTuple; (PhreakJoinNode.java:347)
  at org.drools.core.phreak.PhreakJoinNode.doRightUpdates(Lorg/drools/core/reteoo/JoinNode;Lorg/drools/core/reteoo/LeftTupleSink;Lorg/drools/core/reteoo/BetaMemory;Lorg/drools/core/common/InternalWorkingMemory;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/TupleSets;)V (PhreakJoinNode.java:320)
  at org.drools.core.phreak.PhreakJoinNode.doNode(Lorg/drools/core/reteoo/JoinNode;Lorg/drools/core/reteoo/LeftTupleSink;Lorg/drools/core/reteoo/BetaMemory;Lorg/drools/core/common/InternalWorkingMemory;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/TupleSets;)V (PhreakJoinNode.java:59)
  at org.drools.core.phreak.RuleNetworkEvaluator.switchOnDoBetaNode(Lorg/drools/core/common/NetworkNode;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/InternalWorkingMemory;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/TupleSets;Lorg/drools/core/reteoo/LeftTupleSinkNode;Lorg/drools/core/reteoo/BetaMemory;Lorg/drools/core/reteoo/AccumulateNode$AccumulateMemory;)V (RuleNetworkEvaluator.java:569)
  at org.drools.core.phreak.RuleNetworkEvaluator.evalBetaNode(Lorg/drools/core/reteoo/PathMemory;Lorg/drools/core/common/NetworkNode;Lorg/drools/core/common/Memory;[Lorg/drools/core/reteoo/SegmentMemory;ILorg/drools/core/common/TupleSets;Lorg/drools/core/common/InternalAgenda;Lorg/drools/core/util/LinkedList;ZLorg/drools/core/phreak/RuleExecutor;Lorg/drools/core/common/TupleSets;Lorg/drools/core/common/TupleSets;Lorg/drools/core/reteoo/LeftTupleSinkNode;)Z (RuleNetworkEvaluator.java:555)
  at org.drools.core.phreak.RuleNetworkEvaluator.evalNode(Lorg/drools/core/reteoo/PathMemory;Lorg/drools/core/common/NetworkNode;JLorg/drools/core/common/Memory;[Lorg/drools/core/reteoo/SegmentMemory;ILorg/drools/core/common/InternalAgenda;Lorg/drools/core/util/LinkedList;ZLorg/drools/core/phreak/RuleExecutor;Lorg/drools/core/common/TupleSets;Lorg/drools/core/reteoo/SegmentMemory;Lorg/drools/core/common/TupleSets;Lorg/drools/core/reteoo/LeftTupleSinkNode;)Lorg/drools/core/common/TupleSets; (RuleNetworkEvaluator.java:382)
  at org.drools.core.phreak.RuleNetworkEvaluator.innerEval(Lorg/drools/core/reteoo/PathMemory;Lorg/drools/core/common/NetworkNode;JLorg/drools/core/common/Memory;[Lorg/drools/core/reteoo/SegmentMemory;ILorg/drools/core/common/TupleSets;Lorg/drools/core/common/InternalAgenda;Lorg/drools/core/util/LinkedList;ZLorg/drools/core/phreak/RuleExecutor;)V (RuleNetworkEvaluator.java:342)
  at org.drools.core.phreak.RuleNetworkEvaluator.outerEval(Lorg/drools/core/reteoo/PathMemory;Lorg/drools/core/common/NetworkNode;JLorg/drools/core/common/Memory;[Lorg/drools/core/reteoo/SegmentMemory;ILorg/drools/core/common/TupleSets;Lorg/drools/core/common/InternalAgenda;Lorg/drools/core/util/LinkedList;ZLorg/drools/core/phreak/RuleExecutor;)V (RuleNetworkEvaluator.java:178)
  at org.drools.core.phreak.RuleNetworkEvaluator.evaluateNetwork(Lorg/drools/core/reteoo/PathMemory;Lorg/drools/core/phreak/RuleExecutor;Lorg/drools/core/common/InternalAgenda;)V (RuleNetworkEvaluator.java:136)
  at org.drools.core.phreak.RuleExecutor.reEvaluateNetwork(Lorg/drools/core/common/InternalAgenda;)V (RuleExecutor.java:215)
  at org.drools.core.phreak.RuleExecutor.evaluateNetworkAndFire(Lorg/drools/core/common/InternalAgenda;Lorg/kie/api/runtime/rule/AgendaFilter;II)I (RuleExecutor.java:89)
  at org.drools.core.concurrent.AbstractRuleEvaluator.internalEvaluateAndFire(Lorg/kie/api/runtime/rule/AgendaFilter;IILorg/drools/core/phreak/RuleAgendaItem;)I (AbstractRuleEvaluator.java:33)
  at org.drools.core.concurrent.SequentialRuleEvaluator.evaluateAndFire(Lorg/kie/api/runtime/rule/AgendaFilter;IILorg/drools/core/common/InternalAgendaGroup;)I (SequentialRuleEvaluator.java:43)
  at org.drools.core.common.DefaultAgenda.fireLoop(Lorg/kie/api/runtime/rule/AgendaFilter;ILorg/drools/core/common/DefaultAgenda$RestHandler;Z)I (DefaultAgenda.java:1115)
  at org.drools.core.common.DefaultAgenda.internalFireAllRules(Lorg/kie/api/runtime/rule/AgendaFilter;IZ)I (DefaultAgenda.java:1062)
  at org.drools.core.common.DefaultAgenda.fireAllRules(Lorg/kie/api/runtime/rule/AgendaFilter;I)I (DefaultAgenda.java:1054)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.internalFireAllRules(Lorg/kie/api/runtime/rule/AgendaFilter;I)I (StatefulKnowledgeSessionImpl.java:1347)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules(Lorg/kie/api/runtime/rule/AgendaFilter;I)I (StatefulKnowledgeSessionImpl.java:1338)
  at org.drools.core.impl.StatefulKnowledgeSessionImpl.fireAllRules()I (StatefulKnowledgeSessionImpl.java:1322)
  at org.optaplanner.core.impl.score.stream.drools.DroolsConstraintSession.calculateScore(I)Lorg/optaplanner/core/api/score/Score; (DroolsConstraintSession.java:72)
  at org.optaplanner.core.impl.score.director.stream.ConstraintStreamScoreDirector.calculateScore()Lorg/optaplanner/core/api/score/Score; (ConstraintStreamScoreDirector.java:74)
  at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(Lorg/optaplanner/core/impl/heuristic/move/Move;ZLjava/util/function/Consumer;)V (AbstractScoreDirector.java:225)
  at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.doMove(Lorg/optaplanner/core/impl/localsearch/scope/LocalSearchMoveScope;)V (LocalSearchDecider.java:133)
  at org.optaplanner.core.impl.localsearch.decider.LocalSearchDecider.decideNextStep(Lorg/optaplanner/core/impl/localsearch/scope/LocalSearchStepScope;)V (LocalSearchDecider.java:117)
  at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(Lorg/optaplanner/core/impl/solver/scope/SolverScope;)V (DefaultLocalSearchPhase.java:71)
  at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(Lorg/optaplanner/core/impl/solver/scope/SolverScope;)V (AbstractSolver.java:99)
  at org.optaplanner.core.impl.solver.DefaultSolver.solve(Ljava/lang/Object;)Ljava/lang/Object; (DefaultSolver.java:163)
  at myCalculateClass.calculate
  at mySwingWorker.doInBackground()
  at javax.swing.SwingWorker.call()Ljava/lang/Object; (SwingWorker.java:304)
  at java.util.concurrent.FutureTask.run()V (FutureTask.java:264)
  at javax.swing.SwingWorker.run()V (SwingWorker.java:343)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(Ljava/util/concurrent/ThreadPoolExecutor$Worker;)V (ThreadPoolExecutor.java:1128)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run()V (ThreadPoolExecutor.java:628)
  at java.lang.Thread.run()V (Thread.java:829)

(只是 repeating/extending @hornisgrinde 的评论在这里所以这个问题有一个明确的答案。)

运行 mvn dependency:tree(或等效的 gradle 命令),确保所有 optaplanner-* 和 drools-* 版本同步。

在这种情况下,类路径同时包含 optaplanner-test 8.3.0 和 optaplanner-core 8.7.0,我相信它们被 optaplanner-tests 对 optaplanner-core 的传递依赖所掩盖。为了完全避免这个问题,使用 optaplanner-bom

<project>
  ...
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.optaplanner</groupId>
        <artifactId>optaplanner-bom</artifactId>
        <type>pom</type>
        <version>8.8.0.Final</version>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.optaplanner</groupId>
      <artifactId>optaplanner-core</artifactId>
    </dependency>
    <dependency>
      <groupId>org.optaplanner</groupId>
      <artifactId>optaplanner-test</artifactId>
      <scope>test</scope>
    </dependency>
    ...
  </dependencies>
</project>