Monitoramento de recursos de domínio de aplicativo

O ARM (Monitoramento de recursos de domínio do aplicativo) permite que os hosts monitorem o uso de CPU e memória por domínio do aplicativo. Isso é útil para hosts como o ASP.NET que usam vários domínios do aplicativo em um processo de longa execução. O host pode descarregar o domínio do aplicativo de um aplicativo que está prejudicando o desempenho de todo o processo, mas apenas se puder identificar o aplicativo problemático. O ARM fornece informações que podem ser usadas para ajudar a tomar essas decisões.

Por exemplo, um serviço de hospedagem pode ter vários aplicativos em execução em um servidor do ASP.NET. Se um aplicativo no processo começar a consumir muita memória ou muito tempo do processador, o serviço de hospedagem poderá usar ARM para identificar o domínio do aplicativo que está causando o problema.

O ARM é suficientemente leve para usar em aplicativos ativos. Você pode acessar as informações usando o ETW (Rastreamento de Eventos para Windows) ou diretamente por meio de APIs gerenciadas ou nativas.

Habilitar o monitoramento de recursos

O ARM pode ser habilitado de quatro maneiras: fornecendo um arquivo de configuração na inicialização do CLR (common language runtime), usando uma API de hospedagem não gerenciada, usando código gerenciado ou escutando eventos ETW do ARM.

Após a habilitação do ARM, ele começará coletando dados sobre todos os domínios do aplicativo no processo. Se um domínio do aplicativo tiver sido criado antes de o ARM ser habilitado, os dados cumulativos começarão quando o ARM for habilitado, não quando o domínio do aplicativo foi criado. Após a habilitação, o ARM não poderá ser desabilitado.

  • Você pode habilitar o ARM na inicialização do CLR adicionando o elemento <appDomainResourceMonitoring> ao arquivo de configuração e configurando o atributo enabled como true. Um valor de false (o padrão) significa apenas que o ARM não está habilitado na inicialização; você pode ativá-lo mais tarde usando um dos outros mecanismos de ativação.

  • O host pode habilitar o ARM solicitando a interface de hospedagem ICLRAppDomainResourceMonitor. Após a obtenção bem-sucedida dessa interface, o ARM será habilitado.

  • O código gerenciado pode habilitar o ARM definindo a propriedade estática (Shared no Visual Basic) AppDomain.MonitoringIsEnabled como true. Assim que a propriedade for definida, o ARM estará habilitado.

  • Você pode habilitar o ARM após a inicialização escutando eventos ETW. O ARM é habilitado e começa a acionar eventos para todos os domínios do aplicativo quando você habilita o provedor público Microsoft-Windows-DotNETRuntime usando a palavra-chave AppDomainResourceManagementKeyword. Para correlacionar os dados com domínios do aplicativo e threads, você também deve habilitar o provedor Microsoft-Windows-DotNETRuntimeRundown com a palavra-chave ThreadingKeyword.

Usar ARM

O ARM fornece o tempo total do processador usado por um domínio do aplicativo e três tipos de informações sobre o uso da memória.

  • Total de tempo do processador para um domínio do aplicativo, em segundos: isso é calculado somando os tempos de thread informados pelo sistema operacional de todos os threads que gastaram tempo executando no domínio do aplicativo durante seu ciclo de vida. Threads bloqueados ou em suspensão não usam o tempo do processador. Quando um thread chama um código nativo, o tempo gasto pelo thread no código nativo é incluído na contagem para o domínio de aplicativo em que a chamada foi feita.

  • Total de alocações gerenciadas feitas por um domínio do aplicativo durante seu ciclo de vida, em bytes: o total de alocações nem sempre reflete o uso da memória por um domínio do aplicativo, pois os objetos alocados podem ser de curta duração. No entanto, se um aplicativo alocar e liberar grandes quantidades de objetos, o custo das alocações poderá ser considerável.

  • Memória gerenciada, em bytes, referenciada por um domínio do aplicativo e que sobreviveu à coleta de bloqueio completa mais recente: esse número será preciso somente após uma coleta de bloqueio completa. (Isso contrasta com coleções simultâneas, que ocorrem em segundo plano e não bloqueiam o aplicativo.) Por exemplo, a sobrecarga do método GC.Collect() causa uma coleção completa de bloqueio.

  • Memória total gerenciada, em bytes, referenciada pelo processo e que sobreviveu à coleta de bloqueio completa mais recente: a memória restante para domínios de aplicativos individuais pode ser comparada com esse número.

Determinar quando uma coleta de bloqueio completa ocorreu

Para determinar quando as contagens de memória restante são precisas, você precisa saber quando ocorreu uma coleta de bloqueio completa. O método para fazer isso depende da API usada para examinar as estatísticas do ARM.

API gerenciada

Se você usar as propriedades da classe AppDomain, poderá usar o método GC.RegisterForFullGCNotification para se registrar e receber uma notificação de coletas completas. O limite usado não é importante, pois você está aguardando a conclusão de uma coleta, e não a aproximação de uma coleta. Depois, você pode chamar o método GC.WaitForFullGCComplete, que bloqueia até que uma coleta completa seja concluída. Você pode criar um thread que chama o método em um loop e que realiza qualquer análise necessária sempre que o método retornar.

Como alternativa, você pode chamar o método GC.CollectionCount periodicamente para verificar se a contagem de coletas de geração 2 aumentou. Dependendo da frequência de sondagem, talvez essa técnica não seja uma indicação tão precisa da ocorrência de uma coleta completa.

API de hospedagem

Se você usar a API de hospedagem não gerenciada, o host deverá passar ao CLR uma implementação da interface IHostGCManager. O CLR chama o método Ihostgcmanager quando ele retoma a execução de threads que foram suspensos durante uma coleta. O CLR passa a geração da coleta concluída como um parâmetro do método, para que o host possa determinar se a coleta foi completa ou parcial. Sua implementação do método Ihostgcmanager pode consultar a existência de memória restante, a fim de certificar-se de que as contagens são recuperadas assim que forem atualizadas.

Confira também