Ciclo de vida do Actor, libertação automática da memória e eliminação manual
Um ator é ativado na primeira vez que uma chamada é feita para qualquer um dos seus métodos. Um ator é desativado (lixo coletado pelo tempo de execução de Atores) se não for usado por um período de tempo configurável. Um ator e seu estado também podem ser excluídos manualmente a qualquer momento.
Ativação do ator
Quando um ator é ativado, ocorre o seguinte:
- Quando chega uma chamada para um ator e um ainda não está ativo, um novo ator é criado.
- O estado do ator é carregado se estiver mantendo o estado.
- O
OnActivateAsync
método (C#) ouonActivateAsync
(Java) (que pode ser substituído na implementação do ator) é chamado. - O ator agora é considerado ativo.
Desativação do ator
Quando um ator é desativado, ocorre o seguinte:
- Quando um ator não é usado por algum período de tempo, ele é removido da tabela Atores Ativos.
- O
OnDeactivateAsync
método (C#) ouonDeactivateAsync
(Java) (que pode ser substituído na implementação do ator) é chamado. Isso limpa todos os temporizadores para o ator. Operações de ator, como alterações de estado, não devem ser chamadas a partir desse método.
Gorjeta
O tempo de execução do Fabric Actors emite alguns eventos relacionados à ativação e desativação do ator. Eles são úteis em diagnósticos e monitoramento de desempenho.
Ator coleta de lixo
Quando um ator é desativado, as referências ao objeto ator são liberadas e ele pode ser coletado normalmente pelo coletor de lixo Common Language Runtime (CLR) ou Java Virtual Machine (JVM). A coleta de lixo apenas limpa o objeto do ator; ele não remove o estado armazenado no Gestor de Estado do ator. Na próxima vez que o ator for ativado, um novo objeto ator será criado e seu estado será restaurado.
O que conta como "ser usado" para fins de desativação e coleta de lixo?
- Receber uma chamada
IRemindable.ReceiveReminderAsync
método que está sendo invocado (aplicável somente se o ator usar lembretes)
Nota
Se o ator usa temporizadores e seu retorno de chamada de temporizador é invocado, ele não conta como "em uso".
Antes de entrarmos nos detalhes da desativação, é importante definir os seguintes termos:
- Intervalo de varredura. Este é o intervalo no qual o tempo de execução de Atores verifica sua tabela de Atores Ativos em busca de atores que possam ser desativados e lixo coletado. O valor padrão para isso é 1 minuto.
- Tempo limite ocioso. Esta é a quantidade de tempo que um ator precisa para permanecer sem uso (ocioso) antes de poder ser desativado e o lixo coletado. O valor padrão para isso é 60 minutos.
Normalmente, não é necessário alterar esses padrões. No entanto, se necessário, esses intervalos podem ser alterados ao ActorServiceSettings
registrar seu Serviço de Ator:
public class Program
{
public static void Main(string[] args)
{
ActorRuntime.RegisterActorAsync<MyActor>((context, actorType) =>
new ActorService(context, actorType,
settings:
new ActorServiceSettings()
{
ActorGarbageCollectionSettings =
new ActorGarbageCollectionSettings(10, 2)
}))
.GetAwaiter()
.GetResult();
}
}
public class Program
{
public static void main(String[] args)
{
ActorRuntime.registerActorAsync(
MyActor.class,
(context, actorTypeInfo) -> new FabricActorService(context, actorTypeInfo),
timeout);
}
}
Para cada ator ativo, o tempo de execução do ator controla a quantidade de tempo que esteve ocioso (ou seja, não foi usado). O tempo de execução do ator verifica cada um dos atores ScanIntervalInSeconds
para ver se pode ser lixo coletado e marca se ele esteve ocioso por IdleTimeoutInSeconds
.
Sempre que um ator é usado, seu tempo ocioso é redefinido para 0. Depois disso, o ator só pode ser recolhido se permanecer ocioso por IdleTimeoutInSeconds
. Lembre-se de que um ator é considerado usado se um método de interface do ator ou um retorno de chamada de lembrete do ator for executado. Um ator não é considerado como tendo sido usado se seu retorno de chamada do temporizador for executado.
O diagrama a seguir mostra o ciclo de vida de um único ator para ilustrar esses conceitos.
O exemplo mostra o impacto das chamadas, lembretes e temporizadores do método do ator no tempo de vida desse ator. Vale a pena mencionar os seguintes pontos sobre o exemplo:
- ScanInterval e IdleTimeout são definidos como 5 e 10, respectivamente. (As unidades não importam aqui, uma vez que nosso propósito é apenas ilustrar o conceito.)
- A varredura para que os atores sejam coletados acontece em T=0,5,10,15,20,25, conforme definido pelo intervalo de varredura de 5.
- Um temporizador periódico é acionado em T=4,8,12,16,20,24 e seu retorno de chamada é executado. Não impacta o tempo ocioso do ator.
- Uma chamada de método de ator em T=7 redefine o tempo ocioso para 0 e atrasa a coleta de lixo do ator.
- Um retorno de chamada de lembrete do ator é executado em T = 14 e atrasa ainda mais a coleta de lixo do ator.
- Durante a varredura de coleta de lixo em T = 25, o tempo ocioso do ator finalmente excede o tempo ocioso de 10, e o ator é coletado lixo.
Um ator nunca será coletado lixo enquanto estiver executando um de seus métodos, não importa quanto tempo seja gasto na execução desse método. Como mencionado anteriormente, a execução de métodos de interface do ator e retornos de chamada de lembrete evita a coleta de lixo redefinindo o tempo ocioso do ator para 0. A execução de retornos de chamada do temporizador não redefine o tempo ocioso para 0. No entanto, a coleta de lixo do ator é adiada até que o retorno de chamada do temporizador tenha concluído a execução.
Excluindo manualmente os atores e seu estado
A coleta de lixo de atores desativados apenas limpa o objeto do ator, mas não remove os dados armazenados no State Manager de um ator. Quando um ator é reativado, seus dados são novamente disponibilizados a ele através do Gestor Estadual. Nos casos em que os atores armazenam dados no State Manager e são desativados, mas nunca reativados, pode ser necessário limpar seus dados. Para obter exemplos de como excluir atores, leia excluir atores e seu estado.