Akka:意外的邮箱填满了

时间:2016-10-05 09:23:15

标签: java akka

我有这个简单的代码:

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之后开始以不同的方式工作。

1 个答案:

答案 0 :(得分:4)

这是一个“调试我的代码”问题,不确定它是否应该在这里,但无论如何我都会回答。

调度程序不会将消息排入actor的邮箱本身,它会使用给定的调度程序来执行此操作。由于您阻止默认调度程序中的线程并使用它来进行排队,因此来自调度程序的消息不再到达邮箱(我假设您的默认调度程序有30个线程)。更准确地说:他们一个接一个地到达它,而演员在每个回合中处理最多五条消息。

所以,没有GC编辑,你只是在另一个地方(默认调度程序)排队一个不同的东西(Runnable)。如果处理时间大于滴答期,您的程序将无法持续工作。