【问题标题】:Akka: Cleanup of dynamically created actors necessary when they have finished?Akka:动态创建的 Actor 完成后需要清理它们吗?
【发布时间】:2018-01-20 22:25:26
【问题描述】:

我已经使用 Akka 及其 Java API UntypedActor 实现了一个 Actor 系统。在其中,一个参与者(A 类)使用getContext().actorOf(...); 按需动态启动其他参与者(B 类)。那些 B 演员会做一些 A 不再关心的计算。但是我在想:那些B型演员完成后有必要清理吗?如果有,怎么做?

  • 让 B 演员在完成后致电 getContext().stop(getSelf())
  • 通过让 B 演员在完成后致电 getSelf().tell(Actors.poisonPill());? [这是我现在正在使用的]。
  • 什么都不做?
  • 由...?

文档对此并不清楚,或者我忽略了它。我对 Scala 有一些基本的了解,但 Akka 的源代码并不完全是入门级的东西......

【问题讨论】:

    标签: java akka resource-cleanup


    【解决方案1】:

    您所描述的是根据“请求”(在 A 的上下文中定义)创建的单一用途参与者,它们处理一系列事件然后完成,对吗?这绝对没问题,你关闭它们是对的:如果你不这样做,它们会随着时间的推移而累积,你会遇到内存泄漏。最好的方法是您提到的第一种可能性(最直接),但第二种也可以。

    一些背景知识:演员在其父级中注册以便可识别(例如,在远程处理中需要,但在其他地方也需要),这种注册可以防止他们被垃圾收集。 OTOH,每个父母都有权访问它创建的孩子,因此没有自动终止(即由 Akka)是有意义的,而是需要在用户代码中显式关闭。

    【解决方案2】:

    除了 Roland Kuhn 的回答之外,您可以创建一组预定义的共享同一调度程序的参与者,或者您可以使用将请求分发到参与者池的路由器,而不是为每个请求创建一个新的参与者。

    例如,Balancing Pool Router 允许您让特定类型的一组固定参与者共享同一个邮箱:

    akka.actor.deployment {
      /parent/router9 {
        router = balancing-pool
        nr-of-instances = 5
      }
    }
    

    阅读dispatchersrouting 上的文档了解更多详情。

    【讨论】:

      【解决方案3】:

      我正在分析(visualvm)来自 AKKA 文档的示例集群应用程序之一,我看到垃圾收集在每次 GC 期间清理了每个请求的参与者。无法完全理解使用后明确杀死actor的建议。我的actorsystem 和actors 由SPRING IOC 容器管理,我使用spring 扩展间接actor-producer 来创建actors。 “aggregator”参与者在每次 GC 上都收集垃圾,我确实监控了可视 VM 中的实例数。

      @Component
      @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
      public class StatsService extends AbstractActor {
      
          private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);
      
          @Autowired
          private ActorSystem actorSystem;
      
          private ActorRef workerRouter;
      
          @Override
          public void preStart() throws Exception {
              System.out.println("Creating Router" + this.getClass().getCanonicalName());
             workerRouter = getContext().actorOf(SPRING_PRO.get(actorSystem)
                  .props("statsWorker").withRouter(new FromConfig()), "workerRouter"); 
              super.preStart();
          }
      
          @Override
          public Receive createReceive() {
              return receiveBuilder()
                  .match(StatsJob.class, job -> !job.getText().isEmpty(), job -> {
                      final String[] words = job.getText().split(" ");
                      final ActorRef replyTo = sender();
                      final ActorRef aggregator = getContext().actorOf(SPRING_PRO.get(actorSystem)
                          .props("statsAggregator", words.length, replyTo));
      
                      for (final String word : words) {
                          workerRouter.tell(new ConsistentHashableEnvelope(word, word),
                              aggregator);
                      }
                  })
                  .build();
          }
      }
      

      【讨论】:

        【解决方案4】:

        默认情况下,Actor 不会消耗太多内存。如果应用程序打算稍后使用 actor b,您可以让它们保持活动状态。如果没有,您可以通过毒丸关闭它们。只要你的演员不持有资源,离开演员应该没问题。

        【讨论】:

        • 但是,正如 Roland 指出的那样,actor 不会被垃圾收集,因此会随着时间的推移而积累 => 内存泄漏。
        猜你喜欢
        • 1970-01-01
        • 2011-01-02
        • 2016-10-09
        • 1970-01-01
        • 2018-07-17
        • 1970-01-01
        • 2011-10-03
        • 2019-08-09
        • 1970-01-01
        相关资源
        最近更新 更多