我有这个简单的代码:
List<ActorRef> actors = new ArrayList<>();
for (int i = 0; i < ACTOR_COUNT; i++) {
actors.add(system.actorOf(...));
}
for (ActorRef actor : actors) {
system.scheduler().schedule(FiniteDuration.create(0, TimeUnit.MILLISECONDS),
FiniteDuration.create(1000, TimeUnit.MILLISECONDS), actor, "Run", system.dispatcher(), null);
}
它创建了许多actor,然后为每个actor创建一个调度程序。 Actor本身负责查询MQ然后处理消息。
ACTOR_COUNT&gt; 30,一切都很好。但否则,我们有内存泄漏(带有“运行”消息的akka.dispatch.Envelopes实例正在填满,无法进行垃圾回收)
这很奇怪,因为当我们有更多的演员时,我们会有更多的消息(每个消息每秒1个) - 但是当有更多的演员/消息时,意外的是STOPS填满了。
时间间隔(1000毫秒)并不会真正影响情况,只会使速度变慢或变快。
你可以帮我解释一下这个行为吗?
谢谢。
更新
这是一个虚拟演员,可以帮助隔离问题。
public class MessageQueueTestActor extends UntypedActor {
private static final Logger log = LoggerFactory.getLogger(MessageQueueTestActor.class);
@Override
public void onReceive(Object message) throws Exception {
Thread.sleep(3000);
}
}
使用ACTOR_COUNT = 5重现问题。现在很明显,当演员睡眠时间>调度程序间隔,信封正在填满。如果我将睡眠时间从3000毫秒减少到500毫秒,问题就会消失。
但是如果我将演员数量增加到30(具有相同的休眠时间= 3000ms),则消息也可用于垃圾收集器。为什么?看起来像Akka中的东西在那个threashold之后开始以不同的方式工作。
答案 0 :(得分:4)
这是一个“调试我的代码”问题,不确定它是否应该在这里,但无论如何我都会回答。
调度程序不会将消息排入actor的邮箱本身,它会使用给定的调度程序来执行此操作。由于您阻止默认调度程序中的线程并使用它来进行排队,因此来自调度程序的消息不再到达邮箱(我假设您的默认调度程序有30个线程)。更准确地说:他们一个接一个地到达它,而演员在每个回合中处理最多五条消息。
所以,没有GC编辑,你只是在另一个地方(默认调度程序)排队一个不同的东西(Runnable)。如果处理时间大于滴答期,您的程序将无法持续工作。