Exercício 2 – Acompanhar alocações de processo do modo de usuário
As alocações de heap são feitas diretamente por meio de APIs de Heap (alocações HeapAlloc, HeapRealloc e C/C++, como new, alloc, realloc, calloc) e são atendidas usando três tipos de heaps:
Heap NT de linha principal – solicitações de alocação de serviços de tamanhos inferiores a 64 KB.
Heap de fragmentação baixa – composto por sub-segmentos que fazem solicitações de alocação de serviço de blocos de tamanho fixo.
VirtualAlloc – solicitações de alocação de serviços de tamanhos maiores que 64 KB.
VirtualAlloc é usado para grandes alocações de memória dinâmica que são feitas diretamente por meio da API VirtualAlloc . O uso típico geralmente é para bitmaps ou buffers. Você pode usar VirtualAlloc para reservar um bloco de páginas e, em seguida, fazer chamadas adicionais para VirtualAlloc para confirmar páginas individuais do bloco reservado. Isso permite que um processo reserve um intervalo de seu espaço de endereço virtual sem consumir armazenamento físico até que seja necessário.
Há dois conceitos a serem compreendidos nesta área:
Memória reservada: reserva um intervalo de endereços para uso, mas não adquire recursos de memória.
Memória confirmada: garante que a memória física ou o espaço de arquivo de página estarão disponíveis se os endereços forem referenciados.
Neste exercício, você aprenderá a coletar rastreamentos para investigar como um processo de modo de usuário aloca memória.
O exercício se concentra em um processo de teste fictício chamado MemoryTestApp.exe que aloca memória por meio de:
A API VirtualAlloc para confirmar buffers de memória grandes.
O novo operador C++ para instanciar objetos pequenos.
Você pode baixar MemoryTestApp.exeaqui.
Etapa 1: Coletar um rastreamento virtualAlloc/heap usando o WPR
Alocações de memória grandes geralmente são as que afetam o volume de um processo e são atendidas pela API VirtualAlloc . É aí que todas as investigações devem começar, mas também é possível que um processo se comporte mal com alocações menores (por exemplo, vazamentos de memória usando o novo operador em C++, etc.). O rastreamento de heap se torna útil quando essa situação acontece.
Etapa 1.1: Preparar o sistema para rastreamento de heap
O rastreamento de heap deve ser considerado opcional e feito quando a análise VirtualAlloc não fornece nenhuma explicação relevante para um problema de uso de memória. O rastreamento de heap tende a produzir rastreamentos maiores e é recomendável habilitar o rastreamento somente para os processos individuais que você está investigando.
Adicione a chave do Registro para o processo de interesse (MemoryTestApp.exe neste caso); O rastreamento de heap é habilitado para cada criação de processo subsequente.
reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /t REG_DWORD /d 1 /f
Etapa 1.2: capturar um rastreamento usando o WPR
Nesta etapa, você coletará um rastreamento usando o WPR que contém dados VirtualAlloc e Heap .
Abra o WPR e modifique a configuração de rastreamento.
Selecione os provedores VirtualAlloc e Heap .
Selecione geral como o cenário de desempenho.
Selecione geral como o modo de registro em log.
Clique em Iniciar para iniciar o rastreamento.
Inicie MemoryTestApp.exee aguarde o término do processo (deve levar cerca de 30 segundos).
Retorne ao WPR, salve o rastreamento e abra-o com o Windows Performance Analyzer (WPA).
Abra o menu Rastreamento e selecione Configurar caminho de símbolos.
- Especifique o caminho do cache de símbolos. Para obter mais informações sobre símbolos, consulte a página Suporte a Símbolos no MSDN.
Abra o menu Rastreamento e selecione Carregar símbolos.
Agora você tem um rastreamento que contém todos os padrões de alocação de memória para o processo deMemoryTestApp.exe durante seu tempo de vida.
Etapa 2: Examinar alocações dinâmicas virtualAlloc
Os dados detalhados do VirtualAlloc são expostos por meio do grafo 'Tempos de Vida de Confirmação VirtualAlloc' no WPA. As colunas principais de interesse são as seguintes:
Coluna | Descrição |
---|---|
Processo | O nome do processo que executa alocações de memória por meio de VirtualAlloc. |
Pilha de confirmação | A pilha de chamadas que mostra o caminho do código que leva à alocação de memória. |
Tempo de Confirmação | O carimbo de data/hora de quando a memória foi alocada. |
Hora de Decodificar | O carimbo de data/hora de quando a memória foi liberada. |
Afetando o tamanho | O tamanho das alocações pendentes ou a diferença de tamanho entre o início e o fim do intervalo de tempo selecionado. Esse tamanho é ajustado com base na porta de exibição selecionada. O valor tamanho de impacto será zero se toda a memória alocada por um processo for liberada até o final do intervalo visualizado no WPA. |
Tamanho | A soma cumulativa de toda a alocação durante o intervalo de tempo selecionado. |
Siga estas etapas para analisar MemoryTestApp.exe
Localize o grafo Tempos de Vida de Confirmação VirtualAlloc na categoria Memória da Explorer do Graph.
Arraste e solte os Tempos de Vida de Confirmação VirtualAlloc na guia Análise .
Organize a tabela para mostrar essas colunas. Clique com o botão direito do mouse nos cabeçalhos de coluna para adicionar ou remover colunas.
Processo
Tipo de impacto
Pilha de confirmação
Tempo de Confirmação e Hora de Confirmação
Count
Afetando o tamanho e o tamanho
LocalizeMemoryTestApp.exe na lista de processos.
Aplique um filtro para manter apenas MemoryTestApp.exe no grafo.
- Clique com o botão direito do mouse e selecione Filtrar para Seleção.
O visor de análise deve ser semelhante a este:
No exemplo anterior, dois valores são de interesse:
Tamanho de 126 MB: isso indica que MemoryTestApp.exe alocado um total de 125 MB ao longo de sua vida útil. Ele representa a soma cumulativa de todas as chamadas à API VirtualAlloc feitas pelo processo e suas dependências.
Tamanho de impacto de 0 MB: isso indica que toda a memória alocada pelo processo é liberada até o final do intervalo de tempo que está sendo analisado no momento. O sistema não sofreu com um aumento de seu uso constante de memória de estado.
Etapa 2.1: Analisar o uso de memória de estado estável
Ao investigar a alocação de memória, você deve tentar responder à pergunta: "Por que o uso constante de memória de estado está crescendo para esse cenário?" No exemplo MemoryTestApp.exe , você pode ver que ele tem cerca de 10 MB de memória de estado estável alocada no início e, em seguida, aumenta para 20 MB no meio do caminho.
Para investigar esse comportamento, restrinja o zoom ao redor do intervalo de tempo quando o aumento repentino ocorrer no meio do rastreamento.
Seu visor deve ter esta aparência.
Como você pode ver, o Tamanho de Impacto agora é de 10 MB. Isso significa que, entre o início e o fim do intervalo de tempo que está sendo analisado, há um aumento de 10 MB no uso de memória de estado estável.
Classifique afetando o tamanho clicando no cabeçalho da coluna.
Expanda a linhaMemoryTestApp.exe (na coluna Processo ).
Expanda a linha Impacting (na coluna Tipo de Impacto ).
Navegue pelo processo Pilha de Confirmação até encontrar a função que alocou 10 MB de memória.
Neste exemplo, a função Main de MemoryTestApp.exe aloca 10 MB de memória no meio da carga de trabalho chamando diretamente VirtualAlloc. No mundo real, o desenvolvedor do aplicativo deve determinar se a alocação é razoável ou se o código pode ser reorganizado para minimizar o aumento de uso de memória de estado constante.
Agora você pode desmarmar o visor no WPA.
Etapa 2.2: Analisar o uso transitório (ou de pico) de memória
Ao investigar alocações de memória, você deve tentar responder à pergunta: "Por que há um pico transitório no uso de memória para esta parte do cenário?" Alocações transitórias causam picos no uso de memória e podem levar à fragmentação e enviar conteúdo valioso para fora do cache em espera do sistema quando houver pressão de memória.
No exemplo MemoryTest , você pode ver que há 10 picos diferentes de uso de memória (de 10 MB) distribuídos uniformemente pelo rastreamento.
Reduza o zoom para os últimos quatro picos, para se concentrar em uma região de interesse menor e reduzir o ruído de comportamentos não relevantes.
Seu visor deve ter esta aparência:
Classifique por Tamanho clicando no cabeçalho da coluna.
Expanda a linhaMemoryTestApp.exe (na coluna Processo ).
Clique na linha Transitória (na coluna Tipo de Impacto ).
- Isso deve realçar em azul todos os picos de uso de memória no visor.
Observe o valor das diferentes colunas:
Contagem = 4: isso indica que quatro alocações transitórias de memória foram feitas durante esse intervalo de tempo.
Tamanho de impacto = 0 MB: isso indica que todas as quatro alocações transitórias de memória foram liberadas ao final do intervalo de tempo.
Tamanho = 40 MB: isso indica que a soma de todas as quatro alocações transitórias de memória equivale a 40 MB de memória.
Navegue pelo processo Confirmar Pilha até encontrar as funções que alocaram 40 MB de memória.
Neste exemplo, a função Main de MemoryTestApp.exe chama uma função chamada Operation1, que por sua vez chama uma função chamada ManipulateTemporaryBuffer. Essa função ManipularTemporaryBuffer chama diretamente VirtualAlloc quatro vezes, criando e liberando um buffer de memória de 10 MB todas as vezes. Os buffers duram apenas 100 ms cada. A alocação e os tempos livres dos buffers são representados pelas colunas Tempo de Confirmação e Tempo de Confirmação .
No mundo real, o desenvolvedor de aplicativos determinaria se essas alocações de buffer temporário transitórias de curta duração são necessárias ou se podem ser substituídas usando um buffer de memória permanente para a operação.
Agora você pode desmarmar o visor no WPA.
Etapa 3: Examinar alocações dinâmicas de heap
Até agora, a análise se concentrou apenas em grandes alocações de memória que são atendidas pela API VirtualAlloc . A próxima etapa é determinar se há problemas com outras alocações pequenas feitas pelo processo, usando os dados heap coletados inicialmente.
Os dados detalhados do Heap são expostos por meio do grafo "Alocações de Heap" no WPA. As principais colunas de interesse são as seguintes:
Coluna | Descrição |
---|---|
Processo | O nome do processo que está executando a alocação de memória. |
Handle | O identificador do Heap usado para atender à alocação. Os heaps podem ser criados, portanto, pode haver vários identificadores de heap para o processo. |
Pilha | A pilha de chamadas que mostra o caminho do código que leva à alocação da memória. |
Tempo de Alocação | O carimbo de data/hora de quando a memória foi alocada. |
Afetando o tamanho | O tamanho das alocações pendentes ou a diferença entre o início e o final do visor selecionado. Esse tamanho se ajusta com base no intervalo de tempo selecionado. |
Tamanho | A soma cumulativa de todas as alocações/desalocações. |
Siga estas etapas para analisar MemoryTestApp.exe
Localize o grafo Alocações de Heap na categoria Memória do Explorer do Graph.
Arraste e solte as Alocações de Heap na guia Análise .
Organize a tabela para mostrar estas colunas:
Processo
Handle
Tipo de impacto
Pilha
AllocTime
Count
Afetando tamanho e tamanho
LocalizeMemoryTestApp.exe na lista de processos.
Aplique um filtro para manter apenas MemoryTestApp.exe no grafo.
- Clique com o botão direito do mouse e selecione Filtrar para Seleção.
Seu visor deve ter esta aparência:
Neste exemplo, você pode ver que um dos heaps está aumentando constantemente de tamanho ao longo do tempo a uma taxa constante. Há 1200 alocações de memória nesse heap, representando 130 KB de memória usada até o final do intervalo.
Amplie um intervalo menor (por exemplo, 10 segundos) no meio do rastreamento.
Expanda o identificador de cabeçalho que mostra a maior quantidade de alocações (conforme mostrado na coluna Tamanho impactando ).
Expanda o tipo impactando .
Navegue pelo processo Pilha até encontrar a função responsável por alocar toda essa memória.
Neste exemplo, a função Main de MemoryTestApp.exe chama uma função chamada InnerLoopOperation. Essa função InnerLoopOperation aloca 40 bytes de memória 319 vezes por meio do novo operador C++. Essa memória permanece alocada até que o processo seja encerrado.
No mundo real, o desenvolvedor de aplicativos deve determinar se esse comportamento implica um possível vazamento de memória e corrigir o problema.
Etapa 4: Limpar o sistema de teste
Depois que a análise for concluída, você deverá limpo o registro para garantir que o rastreamento de heap esteja desabilitado para o processo. Execute este comando em um prompt de comando com privilégios elevados:
reg delete "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /f