Este artigo foi traduzido por máquina.

Tudo sobre o CLR

Definindo o perfil do heap coletado como lixo do .NET

S.Ramaswamy e V.Morrison

A MSDN Magazine junho de 2009 artigo "Auditing uso da memória para aplicativos .NET", discutimos monitoramento consumo de memória usando ferramentas como Gerenciador de tarefas, desempenho e VADump. Essas ferramentas ajudam a monitorar o consumo de memória geral do seu aplicativo. Normalmente, se um aplicativo .NET está consumindo uma grande quantidade de memória, ele é ou porque o aplicativo carrega que um grande número de DLLs ou o aplicativo está criando um grande número de objetos de vida útil longa no heap .NET coleta de lixo (GC). Se um aplicativo carrega várias DLLs, o recurso somente (diferente de para evitar desnecessárias dependências) é executar menos código. No entanto, se tiver um aplicativo de uma grande superfície de heap de GC, um pôde identificar o heap de GC foi contribuir significativamente para consumo de memória, como discutido no artigo junho. Neste artigo, nós completar o quadro para problemas de memória heap GC relacionados fornecendo instruções passo a passo sobre como usar o CLR Profiler para investigações de memória de heap de GC .NET.

Recapitular: Todos os aplicativos de auditoria

O runtime do .NET abstrai certas operações (como alocar memória ou usando uma biblioteca de classe grande), e não sempre é simples prever o impacto dessas operações no desempenho do aplicativo. Isso é especialmente verdadeiro para a memória. O ponto importante takeaway no último artigo foi que todos os aplicativos merece uma auditoria periódica de memória. Este artigo passa esse passo a passo usando um programa real como nosso exemplo (em oposição a uma demonstração). Isso era um programa simples e nós pôde tiver escolhido não fazer auditoria de uso da memória ’s o aplicativo. No entanto, quando uma auditoria de memória é concluído, o pequeno esforço de realizar a auditoria liquidado handsomely, como descobrimos ineficiências de memória significativos.

O programa que usa neste artigo é chamado XMLView, que é um simples visualizador para arquivos XML que é altamente escalonável. XMLView pode manipular facilmente arquivos XML que são gigabytes de tamanho (tente que no IE!) porque este aplicativo foi desenvolvido para ser eficiente desde o início de memória. Apesar do design cuidadoso, em alguns cenários, ferramentas como o Gerenciador de tarefas mostraram que o aplicativo estava usando significativamente mais memória que o seria esperado. Este artigo o orienta a investigação descoberta um bug de desempenho.

Uso de memória grande da imagem

A primeira etapa em uma auditoria de memória é para iniciar o aplicativo e examinar o Gerenciador de tarefas OS para verificar o uso de memória geral ’s o aplicativo. Conforme descrito anteriormente, a métrica que é mais importante é "Memória - particular conjunto de trabalho"coluna. Refere-se à memória de aplicativo que não pode ser compartilhada com outros processos em execução na máquina (consulte o artigo anterior para obter detalhes).

Depois que o Gerenciador de tarefas estiver aberto, você pode monitorar o o uso da memória particular do seu aplicativo em tempo real, percorrer vários cenários de usuário e observar qualquer impacto para consumo de memória. Há dois anomalias que garantem sua atenção. Uma é consumo de memória é desproporcional para o cenário ou tarefa que está sendo executada. Por exemplo, abrir uma entrada de menu ou executar operações simples não deve causar grandes picos no consumo de memória. Vazamentos de memória são o segundo tipo de anomalias necessita atenção. Para algumas operações, tais como abrir um novo arquivo, a expectativa é que novas estruturas de dados serão criadas sempre que as operações é executada. No entanto, muitas operações (por exemplo, pesquisas) não alocar logicamente nova memória vida longa. Não é incomum para essas operações sem monitoração de estado alocar memória na primeira vez que são executadas (como estruturas de dados lenta são preenchidas). Mas se o uso de memória continua a aumentar com as iterações subseqüentes do cenário, memória está vazando e precisa ser investigados. Essa técnica de usar o Gerenciador de tarefas é muito grosso do design (somente problemas de memória grande será evidentes), mas para muitos aplicativos, somente os grandes compensam conquistar.

Para XMLView, o cenário é iniciar o visualizador em um arquivo XML grande e executar várias operações de navegação, como abrir nós de árvore ou pesquisa. Nesse experimento inicialmente ligado não vazamentos (o uso de memória estabilizado após um tempo;(consulte do Figura 1). Uso da memória em vez disso substancialmente spiked (8 MB) quando a funcionalidade de pesquisa foi usado (de consulte do Figura 2) do conjunto de trabalho particular 16812KB para 25648KB. Isso representa um dos anomalias que estamos procurando: o consumo de recurso não couberam nosso modelo mental de comportamento de memória ’s o programa, porque a pesquisa tem não estruturas de dados auxiliares e, portanto, não deve consumir memória extra. Tivemos um mistério para resolver.


Figura 1 XMLView memória uso no Gerenciador de tarefas antes da operação de pesquisa


Figura 2 XMLView memória uso no Gerenciador de tarefas após a operação de pesquisa

CLR Profiler

Várias ferramentas de terceiros estão disponíveis para fazer análise de heap de GC .NET;No entanto, irá se concentrar no CLR Profiler, que tem a vantagem de estar disponível como download gratuito da Web da Microsoft. Uma pesquisa na Web em "CLR Profiler"localizará o site de download e a instalação consiste simplesmente em descompactar os arquivos (não há nenhuma etapa de instalação formal). Incluído como parte do pacote, o arquivo Profiler.doc CLR fornece a documentação. Neste artigo, iremos nos concentrar nas partes que são usadas normalmente.

Como funciona o CLR Profiler?

Para usar um gerador de perfil corretamente, você precisará compreender como os dados foram coletados e as limitações da ferramenta. O CLR Profiler usa uma interface especial para o runtime permite que ele obter retornos de chamada quando determinados eventos ocorrem dentro do runtime (msdn.microsoft.com/library/ms404511.aspx). Atualmente, essa interface pode ser usada somente se o processo sendo perfilado for iniciado com um determinado conjunto de variáveis de ambiente que informam o tempo de execução sobre o mecanismo de contato para o gerador de perfil. Portanto, existem algumas limitações, como a incapacidade para anexar a um processo existente. CLR Profiler deve começar o processo com o conjunto de variáveis de ambiente direita. Para serviços que são normalmente iniciados pelo sistema operacional diretamente, como o ASP.NET, procedimentos especiais deve ser seguido (consulte Profiler.doc CLR de download de detalhes). Como um aparte, para certos cenários que adicionamos suporte API para anexar no .NET Framework 4 (mas somente o suporte à API;suporte para anexar a ferramenta de CLR Profiler seguirá logo após).

Quando o CLR Profiler é iniciado o aplicativo, ele fornece opções no tipo de informações coletadas. Por padrão, ele obtém retornos de chamada sempre que um método gerenciado é chamado ou retorna de uma chamada, bem como em cada alocação de heap de GC. Esses retornos de chamada são chamados com freqüência, resultando no programa diminuindo substancialmente e criar log grandes arquivos de mais de 100 MB) para muitos cenários do mundo real. CLR Profiler não medir o tempo de execução e limita próprio para manter o controle de alocações de heap GC somente e o número de vezes que cada método diferente foi chamado. CLR Profiler usa a chamada chamada de método de e eventos de retorno do método para controlar quais métodos estão atualmente ativos na pilha, para que cada alocação de heap e chamada pode ser atribuída com uma pilha de chamadas completa de onde o evento ocorreu. Isso identifica onde os objetos estão sendo criados.

Infelizmente, as informações detalhadas que CLR Profiler coleta por padrão podem tornar o dados coleção processo lento (minutos). No entanto, essas informações detalhadas raramente é necessário. Uma das técnicas mais úteis não requer quaisquer informações adicionais a serem coletados durante a execução normal. Embora seja importante saber onde ocorre a alocação de memória, muitos erros podem ser corrigidos apenas por Noções básicas sobre quem é manter a memória ativo. Para responder esta pergunta último, um não precisa chamar pilhas ou alocação de eventos;em vez disso, apenas um instantâneo simples de heap de GC é necessário. Assim, para a maioria das investigações, um pode desativar todos os log de eventos normal e obter uma boa experiência (razoável perfil desempenho bem como identificar o problema). Essa é a técnica usada aqui.

Usando o CLR Profiler

Se você baixar CLR Profiler da Web e extraia-o para o local padrão, o programa terminarão em C:\CLR Profiler\Binaries\x86\ClrProfiler.exe (há um x64 versão, muito). Iniciar o CLR Profiler exibe o formulário mostrado na do Figura 3.


Figura 3 do CLR Profiler inicialização tela

Esta caixa de diálogo inicialização controla a coleção de dados de perfil. As caixas de seleção indicar que quando o aplicativo é executado, perfil estará ativo e dados de alocação e chamada serão coletados (o arquivo de log será detalhado). Como estamos interessados em somente instantâneos de heap, somente a caixa ativa perfilação precisa permanecer selecionada (as caixas de alocações e chamadas devem estar desmarcadas). Portanto, o CLR Profiler registrará apenas o mínimo durante a execução do programa, manter a capacidade de resposta atualizado e tamanhos de arquivo de log para baixo.

Se o aplicativo que você deseja o perfil não precisar quaisquer argumentos de linha de comando ou a pasta de inicialização especial, você pode simplesmente selecione Iniciar Application e CLR Profiler irá exibir uma caixa de diálogo arquivo seletor para selecionar o aplicativo seja executado. Se você precisa definir parâmetros de linha de comando ou o diretório atual para o aplicativo, você deverá configurá-los usando o arquivo - >Defina menu Parameters antes de clicar em Iniciar o aplicativo.

Tirar um instantâneo de heap

Depois de selecionar o aplicativo executável, CLR Profiler será iniciado imediatamente executando o aplicativo. Porque nós tiver desativado o alocação e chamada de perfil, ele deve executar muito perto para sua velocidade normal. CLR Profiler agora está conectado ao aplicativo e em qualquer ponto você pode selecionar Mostrar pilha agora e obter um instantâneo de heap. O instantâneo de heap para o aplicativo XMLView acontece com a aparência que é exibido no do Figura 4.

Isso é uma representação da heap de GC inteiro (ao vivo somente objetos são exibidos). Enquanto o heap de GC é realmente um gráfico arbitrário, CLR Profiler determina links e formulários uma árvore fora dele, enraizada em um pseudo-node chamado raiz. O tamanho de cada um dos filhos, em seguida, pode ser atribuído aos seus pais para que na raiz, todos os objetos ao vivo tiverem sido contabilizados para. No exemplo acima, a heap de GC tinha 5.4 MB de objetos. Este 5.4 MB não inclui espaço livre no heap de GC não foi alocado e portanto, a quantidade de memória virtual alocada para a pilha é garantida ser maior que (o tamanho exato depende, mas como mencionado no artigo anterior, 1,6 vezes maior é uma boa estimativa).

Em geral, não há mais de um único caminho da raiz para um determinado objeto. CLR Profiler sempre escolhe o caminho mais curto para exibição na árvore de. No entanto, se houver vários caminhos com o mesmo comprimento, a opção é feita arbitrariamente. Além disso, por padrão, CLR Profiler não exibe objetos individuais mas trata todos os objetos que possuem os mesmos tipos de pai e os mesmos tipos de filho como parte do mesmo nó. Essa técnica geralmente faz um bom trabalho de recolhendo nós listas vinculadas e outras estruturas de dados recursivas, simplificando assim o modo de exibição. Se esta agregação não for desejada, você pode desativá-la clicando com o botão direito do mouse e selecionando Mostrar instâncias individuais.

Na parte superior da janela do gráfico de pilha são dois grupos de botão de rádio. A primeira é a escala, que indica a altura de cada caixa no modo de exibição de gráfico. O segundo é o botão detalhes, que determina como grande tem um nó para serem são exibidos. É útil configurar isso para algo muito grosso, para manter o gráfico organizada. Freqüentemente, você está interessado em apenas o gráfico tem algo a ver com um tipo específico (por exemplo, somente sobre objetos do tipo XmlPositions). CLR Profiler permite filtrar neste e em outros critérios (clique em direita - >Filtro).

No exemplo XMLView do Figura 4, a maior parte da heap de GC (5.1 MB) é um filho de uma instância do tipo XmlView. A instância XmlView tem um filho do tipo XmlPositions, que por sua vez tem uma matriz de MB XmlElementPositionInfo 5. XmlElementPositionInfo é a matriz grande que controla o ponto inicial no arquivo de cada marca XML e seu tamanho é proporcional ao tamanho do arquivo XML que está sendo lido (como esse é um arquivo muito grande, espera-se que essa matriz será grande). Portanto, nós concluída que o tamanho da pilha é razoável.


Figura 4 CLR Profiler instantâneo antes da operação de pesquisa

Controle para baixo crescimento de heap de GC

No exemplo XMLView, nosso problema não era com o tamanho inicial de heap de GC, mas o fato de que cresceu significativamente quando foi feita uma pesquisa. Portanto, o que estamos interessados em é a alteração na pilha entre os dois instantâneos. CLR Profiler possui recursos especiais para fazer esse tipo de investigação.

Depois de gerar um instantâneo de heap, pode executar a operação de pesquisa (fazendo com que a memória adicional a ser alocada) e, em seguida, levar outro instantâneo de heap. O resultado é a exibição a seguir:

A memória associada ao objeto XmlView agora foi expandida para 8,5 MB (de 5.1 MB). Os nós têm duas cores, com o vermelho mais claro que representa a memória estava presente no instantâneo anterior. O vermelho mais escuro é a memória que é exclusiva para o novo instantâneo. Assim, a memória nova foi adicionada por um tipo chamado XmlFind (isso não é surpreendente), como pode ser visto no do Figura 5. Rolagem sobre à direita, encontramos que toda essa memória extra foi associado uma matriz de Int64 que pertenciam ao tipo de LineStream, como mostrado na do Figura 6.

Isso foi as informações necessárias para identificar o erro! Acontece que o analisador XML .NET tem a capacidade para obter o número de coluna número de linha de uma marca XML, mas não a posição do arquivo. Para contornar isso, o programa necessário um mapeamento de número da linha a posição do arquivo. A matriz Int64 foi usada para isso. No entanto, o código necessário esse mapeamento somente para XML elemento marca atual, que pode abranger qualquer número de linhas, mas normalmente apenas alguns. Esse mapeamento não foi sendo redefinido pelo código de localização, permitindo que a matriz de mapeamento para aumentar desnecessariamente grande. A correção foi simples, mas esse bug seria provavelmente existem para sempre se a auditoria de memória não foi executada. Usando o CLR Profiler, levou apenas alguns minutos para encontrar as informações que era fundamentais para corrigir esse erro.


Figura 5 CLR Profiler instantâneo após a operação de pesquisa - parte 1


Figura 6 CLR Profiler instantâneo após a operação de pesquisa - parte 2

Exibindo novos objetos autônomo

No exemplo anterior, era relativamente fácil distinguir visualmente por sua cor os objetos exclusivos para o último instantâneo. No entanto, para gráficos de objeto grande, isso é difícil fazer e seria conveniente remover os antigos objetos do gráfico, que pode ser feito usando o CLR Profiler. Esse recurso usa eventos alocação para implementação, portanto, depois de gerar o instantâneo primeiro, você precisará marcar a caixa alocações (você pode deixar a caixa de chamadas não verificado). Depois disso, interagir com o aplicativo até que ele aloca mais memória e selecione Mostrar pilha agora novamente. Ela mostrará a pilha com suas duas cores de vermelho como antes. Agora, você pode clique com o botão direito do mouse na janela e selecione Mostrar novos objetos, e uma nova janela será exibida que mostra somente a parte da heap de GC que foi alocado entre dois instantâneos.

Controle abaixo raízes all para um objeto

Você deve estar imaginando como memória vazamentos podem acontecer em código gerenciado, dado o coletor de lixo eventualmente limpa toda a memória não utilizada. No entanto, há situações onde itens podem permanecer ativos tempo depois que você imagina que poderia ser liberados. Por exemplo, referências não intencionais podem manter objetos gerenciados ativo.

A técnica para o rastreamento de vazamentos de memória é muito semelhante para compreender o consumo de memória desproporcional. A diferença real somente é que para consumo de memória desproporcional, esperamos que o objeto seja na memória (ela apenas não deve ser tão grande), enquanto se há vazamentos, nós não espera o objeto seja no heap de GC em todos os. Usando instantâneos da pilha e o recurso Mostrar novos objetos, é fácil identificar quais objetos não devem estar ativos (usando a sua compreensão do cenário). Se um objeto é sobreviventes no heap, deve haver alguns referência ao objeto. No entanto, se houver mais de uma referência única, você verá remover um link não corrige o problema porque outra referência é mantê-lo ativo. Assim, seria conveniente localizar todos os caminhos da raiz que manter um determinado objeto ativo no heap de GC. CLR Profiler possui suporte especial para fazer isso. Primeiro, o nó de interesse é selecionado. Em seguida, clique com o botão direito do mouse e selecione Mostrar referências e um novo gráfico serão exibida que mostra todos os caminhos da raiz para o objeto em questão. Isso lhe fornecerá informações suficientes para identificar quais referências são manter os objetos ativo no heap. Eliminar os links para o objeto pode corrigir o vazamento de memória.

Obtenção de pilhas de chamada de alocação

Exibir o heap de GC é com freqüência suficiente para diagnosticar a maioria dos problemas de consumo de memória alta. Entretanto, ocasionalmente, é útil entender a pilha de chamada onde ocorreu uma alocação. Para obter essas informações, você precisa selecionar a caixa de seleção alocações antes de executar o programa. Isso faz com que CLR Profiler façam o rastreamento de pilha sempre que uma alocação acontece. Coletar essas informações tornará o arquivo de log maiores, mas ainda geralmente será menor do que 50 MB para aplicativos moderadamente complexos. Você não deve ativar a caixa de seleção chamadas porque isso faz logon em cada entrada de método, que é detalhada (é fácil obter arquivos de log maior do que 100 MB). Essas informações de chamada do método é necessária somente se você estiver usando o CLR Profiler para determinar quais métodos estão sendo chamados com freqüência, e isso não é normalmente útil em uma investigação de memória.

Do gráfico heap, selecione um nó de interesse, clique com o botão direito do mouse e selecione Mostrar quem alocados. Uma nova janela mostrando todas as pilhas de chamadas alocado um objeto em que o nó será exibida. Você também pode acessar os rastreamentos de pilha do modo de exibição - >Alocação de item de menu gráfico. Isso mostra todas as alocações feitas durante o programa atribuído para a pilha de chamada alocado-los. Para investigações de memória, este modo de exibição não é muito útil como muitos dessas alocações são para objetos de curta duração que rapidamente obter recuperados pelo GC e, portanto, não contribuem para consumo de memória geral. No entanto, desde que essas alocações contribuem para o uso da CPU (para alocar e, em seguida, recuperar), este modo de exibição é útil quando seu aplicativo é vinculada à CPU e o profiler de CPU mostra grandes quantidades de tempo gasto no GC. A maneira óbvia para reduzir o tempo no GC é fazer menos alocações e este modo de exibição mostra onde as alocações estão pela pilha de chamada.

Parte do ciclo de vida de desenvolvimento

Neste artigo, nós movimentada por meio de uma investigação de desempenho de memória para o caso comum onde o consumo de memória é dominado por heap .NET GC. Usando o CLR Profiler gratuito e disponível para download, conseguimos facilmente obter instantâneos da pilha GC em vários pontos no aplicativo e comparar os instantâneos uns com os outros. Com o CLR Profiler, ele é fácil realizar auditorias (ele leva apenas alguns minutos) e deve ser parte do ciclo de desenvolvimento de cada aplicativo.

Subramanian Ramaswamy é o gerente de programa para desempenho de CLR na Microsoft. Ele possui Ph.d. Os elétricos e engenharia de computador do Georgia Institute of Technology.

Vance Morrison é gerente de arquiteto e grupo o parceiro de desempenho do CLR na Microsoft. Ele orientou o design do .NET Intermediate Language e está envolvido com o .NET desde seu início.