Added explicit nullification of all ActorRef references in Actor to make the Actor instance eligable for GC
This commit is contained in:
parent
3d973fea9b
commit
05058af370
3 changed files with 96 additions and 13 deletions
2
LICENSE
2
LICENSE
|
|
@ -1,6 +1,6 @@
|
|||
This software is licensed under the Apache 2 license, quoted below.
|
||||
|
||||
Copyright 2009 Scalable Solutions AB [http://scalablesolutions.se]
|
||||
Copyright 2009-2010 Scalable Solutions AB [http://scalablesolutions.se]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
use this file except in compliance with the License. You may obtain a copy of
|
||||
|
|
|
|||
|
|
@ -73,10 +73,11 @@ object Actor extends Logging {
|
|||
val TIMEOUT = config.getInt("akka.actor.timeout", 5000)
|
||||
val SERIALIZE_MESSAGES = config.getBool("akka.actor.serialize-messages", false)
|
||||
|
||||
/** A Receive is the type that defines actor message behavior
|
||||
* currently modeled as a PartialFunction[Any,Unit]
|
||||
/**
|
||||
* A Receive is a convenience type that defines actor message behavior currently modeled as
|
||||
* a PartialFunction[Any, Unit].
|
||||
*/
|
||||
type Receive = PartialFunction[Any,Unit]
|
||||
type Receive = PartialFunction[Any, Unit]
|
||||
|
||||
private[actor] val actorRefInCreation = new scala.util.DynamicVariable[Option[ActorRef]](None)
|
||||
|
||||
|
|
@ -89,6 +90,10 @@ object Actor extends Logging {
|
|||
* actor ! message
|
||||
* actor.stop
|
||||
* </pre>
|
||||
* You can create and start the actor in one statement like this:
|
||||
* <pre>
|
||||
* val actor = actorOf[MyActor].start
|
||||
* </pre>
|
||||
*/
|
||||
def actorOf[T <: Actor: Manifest]: ActorRef = new LocalActorRef(manifest[T].erasure.asInstanceOf[Class[_ <: Actor]])
|
||||
|
||||
|
|
@ -105,6 +110,10 @@ object Actor extends Logging {
|
|||
* actor ! message
|
||||
* actor.stop
|
||||
* </pre>
|
||||
* You can create and start the actor in one statement like this:
|
||||
* <pre>
|
||||
* val actor = actorOf(new MyActor).start
|
||||
* </pre>
|
||||
*/
|
||||
def actorOf(factory: => Actor): ActorRef = new LocalActorRef(() => factory)
|
||||
|
||||
|
|
@ -239,17 +248,57 @@ object Actor extends Logging {
|
|||
* => SHUT DOWN (when 'exit' is invoked) - can't do anything
|
||||
* </pre>
|
||||
*
|
||||
* <p/>
|
||||
* The Actor's API is available in the 'self' member variable.
|
||||
*
|
||||
* <p/>
|
||||
* Here you find functions like:
|
||||
* - !, !!, !!! and forward
|
||||
* - link, unlink, startLink, spawnLink etc
|
||||
* - makeTransactional, makeRemote etc.
|
||||
* - start, stop
|
||||
* - etc.
|
||||
*
|
||||
* <p/>
|
||||
* Here you also find fields like
|
||||
* - dispatcher = ...
|
||||
* - id = ...
|
||||
* - lifeCycle = ...
|
||||
* - faultHandler = ...
|
||||
* - trapExit = ...
|
||||
* - etc.
|
||||
*
|
||||
* <p/>
|
||||
* This means that to use them you have to prefix them with 'self', like this: <tt>self ! Message</tt>
|
||||
*
|
||||
* However, for convenience you can import these functions and fields like below, which will allow you do
|
||||
* drop the 'self' prefix:
|
||||
* <pre>
|
||||
* class MyActor extends Actor {
|
||||
* import self._
|
||||
* id = ...
|
||||
* dispatcher = ...
|
||||
* spawnLink[OtherActor]
|
||||
* ...
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p/>
|
||||
* The Actor trait also has a 'log' member field that can be used for logging within the Actor.
|
||||
*
|
||||
* @author <a href="http://jonasboner.com">Jonas Bonér</a>
|
||||
*/
|
||||
trait Actor extends Logging {
|
||||
//Type alias because traits cannot have companion objects...
|
||||
/**
|
||||
* Type alias because traits cannot have companion objects.
|
||||
*/
|
||||
type Receive = Actor.Receive
|
||||
|
||||
/**
|
||||
/*
|
||||
* For internal use only, functions as the implicit sender references when invoking
|
||||
* one of the message send functions (!, !!, !!! and forward).
|
||||
* one of the message send functions (!, !! and !!!).
|
||||
*/
|
||||
implicit val optionSelf: Option[ActorRef] = {
|
||||
implicit val optionSelf: Option[ActorRef] = {
|
||||
val ref = Actor.actorRefInCreation.value
|
||||
Actor.actorRefInCreation.value = None
|
||||
if (ref.isEmpty) throw new ActorInitializationException(
|
||||
|
|
@ -258,10 +307,15 @@ trait Actor extends Logging {
|
|||
"\n\tYou have to use one of the factory methods in the 'Actor' object to create a new actor." +
|
||||
"\n\tEither use:" +
|
||||
"\n\t\t'val actor = Actor.actorOf[MyActor]', or" +
|
||||
"\n\t\t'val actor = Actor.actorOf(new MyActor(..))'")
|
||||
"\n\t\t'val actor = Actor.actorOf(new MyActor(..))'" +
|
||||
"\n\t\t'val actor = Actor.actor { case msg => .. } }'")
|
||||
else ref
|
||||
}
|
||||
|
||||
/*
|
||||
* For internal use only, functions as the implicit sender references when invoking
|
||||
* the forward function.
|
||||
*/
|
||||
implicit val someSelf: Some[ActorRef] = optionSelf.asInstanceOf[Some[ActorRef]]
|
||||
|
||||
/**
|
||||
|
|
@ -274,13 +328,12 @@ trait Actor extends Logging {
|
|||
*/
|
||||
val self: ActorRef = optionSelf.get
|
||||
self.id = getClass.getName
|
||||
import self._
|
||||
|
||||
/**
|
||||
* User overridable callback/setting.
|
||||
* <p/>
|
||||
* Partial function implementing the actor logic.
|
||||
* To be implemented by subclassing actor.
|
||||
* To be implemented by concrete actor class.
|
||||
* <p/>
|
||||
* Example code:
|
||||
* <pre>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import java.util.concurrent.locks.ReentrantLock
|
|||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.{Map => JMap}
|
||||
import java.lang.reflect.Field
|
||||
|
||||
/**
|
||||
* The ActorRef object can be used to deserialize ActorRef instances from of its binary representation
|
||||
|
|
@ -593,7 +594,11 @@ sealed class LocalActorRef private[akka](
|
|||
|
||||
@volatile private var isInInitialization = false
|
||||
@volatile private var runActorInitialization = false
|
||||
|
||||
|
||||
// Needed to be able to null out the 'val self: ActorRef' member variables to make the Actor
|
||||
// instance eligeble for garbage collection
|
||||
private val actorSelfFields = findActorSelfField(actor.getClass)
|
||||
|
||||
if (runActorInitialization) initializeActorInstance
|
||||
|
||||
/**
|
||||
|
|
@ -720,6 +725,7 @@ sealed class LocalActorRef private[akka](
|
|||
remoteAddress.foreach(address => RemoteClient.unregister(
|
||||
address.getHostName, address.getPort, uuid))
|
||||
RemoteNode.unregister(this)
|
||||
nullOutActorRefReferencesFor(actorInstance.get)
|
||||
} else if (isBeingRestarted) throw new ActorKilledException("Actor [" + toString + "] is being restarted.")
|
||||
}
|
||||
|
||||
|
|
@ -1082,6 +1088,7 @@ sealed class LocalActorRef private[akka](
|
|||
Actor.log.debug("Restarting linked actors for actor [%s].", id)
|
||||
Actor.log.debug("Invoking 'preRestart' for failed actor instance [%s].", id)
|
||||
failedActor.preRestart(reason)
|
||||
nullOutActorRefReferencesFor(failedActor)
|
||||
val freshActor = newActor
|
||||
freshActor.synchronized {
|
||||
freshActor.init
|
||||
|
|
@ -1137,7 +1144,30 @@ sealed class LocalActorRef private[akka](
|
|||
|
||||
protected[akka] def linkedActorsAsList: List[ActorRef] =
|
||||
linkedActors.values.toArray.toList.asInstanceOf[List[ActorRef]]
|
||||
|
||||
|
||||
private def nullOutActorRefReferencesFor(actor: Actor) = {
|
||||
actorSelfFields._1.set(actor, null)
|
||||
actorSelfFields._2.set(actor, null)
|
||||
actorSelfFields._3.set(actor, null)
|
||||
}
|
||||
|
||||
private def findActorSelfField(clazz: Class[_]): Tuple3[Field, Field, Field] = {
|
||||
try {
|
||||
val selfField = clazz.getDeclaredField("self")
|
||||
val optionSelfField = clazz.getDeclaredField("optionSelf")
|
||||
val someSelfField = clazz.getDeclaredField("someSelf")
|
||||
selfField.setAccessible(true)
|
||||
optionSelfField.setAccessible(true)
|
||||
someSelfField.setAccessible(true)
|
||||
(selfField, optionSelfField, someSelfField)
|
||||
} catch {
|
||||
case e: NoSuchFieldException =>
|
||||
val parent = clazz.getSuperclass
|
||||
if (parent != null) findActorSelfField(parent)
|
||||
else throw new IllegalStateException(toString + " is not an Actor since it have not mixed in the 'Actor' trait")
|
||||
}
|
||||
}
|
||||
|
||||
private def initializeActorInstance = if (!isRunning) {
|
||||
dispatcher.register(this)
|
||||
dispatcher.start
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue