Akka:动态创建的Actor完成后是否需要清理?

22
我已经使用Akka及其Java API UntypedActor实现了一个Actor系统。在该系统中,一个Actor(类型A)根据需要动态启动其他Actor(类型B),使用getContext().actorOf(...);。那些B类型的Actor将执行一些计算,但A类型的Actor不再关心它们。但我想知道:当这些B类型的Actor完成任务时,有必要清理它们吗?如果需要,应该如何清理?
  • 当B类型的Actor完成任务时,通过调用getContext().stop(getSelf())来停止它们?
  • 当B类型的Actor完成任务时,通过调用getSelf().tell(Actors.poisonPill());来停止它们?[这是我目前正在使用的方法]。
  • 什么都不做?
  • 通过其他方式?
文档对此并不明确,或者我可能已经忽略了。我有一些Scala基础知识,但Akka源代码并不是入门级别的东西...
4个回答

23
您所描述的是根据“A”的上下文定义创建的单一用途actor,它们处理一系列事件,然后完成任务,对吗?这完全没问题,您关闭它们是正确的:如果不这样做,它们将随着时间的推移累积,并且可能会导致内存泄漏。最好的方法是您提到的第一种可能性(最直接的方法),但第二种方法也可以。

背景介绍一下:actors在其父级中注册以便进行标识(例如在远程调用中和其他地方都需要),并且此注册使它们免于被垃圾收集。另一方面,每个父对象都有权访问其创建的子对象,因此没有自动终止(即由Akka自行处理)是有意义的,而需要用户代码显式关闭。


相关问题:http://stackoverflow.com/questions/23066264/can-wrapping-akka-actors-in-class-actors-caused-memory-leaks - Andrew Cassidy

0
我正在使用VisualVM对AKKA文档中的一个示例集群应用程序进行分析,并且发现垃圾回收在每次GC期间清理每个请求actor。无法完全理解明确杀死actor的建议。我的actorsystem和actors由SPRING IOC容器管理,我使用spring扩展来间接创建actors。 "聚合器"actor在每次GC上都被垃圾回收了,我在visual 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();
    }
}

0
除了Roland Kuhn的回答之外,您可以创建一组预定义的演员,它们共享相同的调度程序,而不是为每个请求创建一个新的演员,或者您可以使用路由器将请求分配给演员池。例如,平衡池路由器允许您拥有特定类型的固定演员集共享同一个邮箱:
akka.actor.deployment {
  /parent/router9 {
    router = balancing-pool
    nr-of-instances = 5
  }
}

请阅读调度程序路由的文档以获取更多详细信息。


-3

默认情况下,Actor 不会占用太多内存。如果应用程序打算稍后使用Actor B,则可以使其保持活动状态。否则,您可以通过 poisonpill 关闭它们。只要您的 actors 没有持有资源,离开 actor 就应该没问题。


4
但正如Roland所指出的那样,演员将不会被垃圾回收,因此随着时间的推移会积累 -> 内存泄漏。 - Robert Petermeier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接