2012-03-05 48 views
21

我已經實現了一個使用Akka及其Java API UntypedActor的Actor系統。其中,一名演員(類型A)根據需要動態地啓動其他演員(類型B),使用getContext().actorOf(...);。那些B演員會做一些A不再真正關心的計算。但是我想知道:是否有必要在完成時清理B型的演員?如果是這樣,怎麼樣?Akka:完成動態創建的演員時需要清理嗎?

  • 通過讓B參與者在完成時調用getContext().stop(getSelf())
  • 通過讓B演員完成時調用getSelf().tell(Actors.poisonPill());? [這是我現在使用的]。
  • 什麼都不做?
  • ...??

這篇文檔不清楚,或者我忽略了它。我對Scala有一些基本的瞭解,但Akka的源代碼並不完全是入門級的東西......

回答

23

你所描述的是每個「請求」(在A的上下文中定義)創建的單一目的actor,它處理一系列事件,然後完成,對嗎?這是絕對好的,你是正確的關閉這些:如果你不這樣做,他們會積累一段時間,你會遇到內存泄漏。做到這一點的最佳方式是你提到的第一個可能性(最直接的),但第二個也是可以的。

有點背景:演員在他們的父母身上註冊以便識別(例如在遠程處理中需要但在其他地方),並且這種註冊使他們免於被垃圾收集。 OTOH,每個父母都有權訪問其創建的孩子,因此不會自動終止(即通過Akka),這意味着需要在用戶代碼中明確關閉。

+0

http:// stackoverflow。com/questions/23066264/can-wrapping-akka-actors-in-class-actors-caused-memory-leaks < - 相關問題 – 2014-04-14 17:33:55

-3

默認情況下,參與者不會消耗太多內存。如果應用程序打算稍後使用actor b,則可以使它們保持活動狀態。如果沒有,你可以通過poisonpill關閉它們。只要你的演員沒有資源,留下一個演員應該沒問題。

+4

但是,正如羅蘭指出的那樣,演員不會被垃圾收集,因此會隨着時間累積=>內存泄漏。 – 2012-03-06 16:21:53

0

除了Roland Kuhn的回答,不是爲每個請求創建一個新角色,而是創建一組預定義的共享相同調度器的角色,或者使用將請求分發給角色池的路由器。

Balancing Pool Router,例如,可以讓你有一組固定的一特定類型的份額的行動者相同的郵箱的:

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

閱讀文檔上dispatchersrouting爲進一步的細節。

0

我正在剖析(visualvm)來自AKKA文檔的示例集羣應用程序之一,並且我在每個GC期間看到清理每個請求演員的垃圾收集。無法完全理解使用後顯式殺死actor的建議。我的演員系統和演員由SPRING IOC容器管理,我使用spring extension直接演員製作人來創建演員。 「聚合器」actor正在每個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(); 
    } 
}