Partilhar via


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:

  1. Heap NT de linha principal – solicitações de alocação de serviços de tamanhos inferiores a 64 KB.

  2. Heap de fragmentação baixa – composto por sub-segmentos que fazem solicitações de alocação de serviço de blocos de tamanho fixo.

  3. 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:

  1. Memória reservada: reserva um intervalo de endereços para uso, mas não adquire recursos de memória.

  2. 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:

  1. A API VirtualAlloc para confirmar buffers de memória grandes.

  2. 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 .

  1. Abra o WPR e modifique a configuração de rastreamento.

    1. Selecione os provedores VirtualAlloc e Heap .

    2. Selecione geral como o cenário de desempenho.

    3. Selecione geral como o modo de registro em log.

      Captura de tela do menu de opções de rastreamento do WPR.

  2. Clique em Iniciar para iniciar o rastreamento.

  3. Inicie MemoryTestApp.exee aguarde o término do processo (deve levar cerca de 30 segundos).

  4. Retorne ao WPR, salve o rastreamento e abra-o com o Windows Performance Analyzer (WPA).

  5. 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.
  6. 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

  1. Localize o grafo Tempos de Vida de Confirmação VirtualAlloc na categoria Memória da Explorer do Graph.

  2. Arraste e solte os Tempos de Vida de Confirmação VirtualAlloc na guia Análise .

  3. 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.

    1. Processo

    2. Tipo de impacto

    3. Pilha de confirmação

    4. Tempo de Confirmação e Hora de Confirmação

    5. Count

    6. Afetando o tamanho e o tamanho

  4. LocalizeMemoryTestApp.exe na lista de processos.

  5. Aplique um filtro para manter apenas MemoryTestApp.exe no grafo.

    • Clique com o botão direito do mouse e selecione Filtrar para Seleção.

Captura de tela mostrando como filtrar os resultados.

O visor de análise deve ser semelhante a este:

Grafo de exemplo da aparência dos dados quando filtrados.

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.

Captura de tela de dados de exemplo mostrando o uso de memória.

Para investigar esse comportamento, restrinja o zoom ao redor do intervalo de tempo quando o aumento repentino ocorrer no meio do rastreamento.

Captura de tela mostrando como ampliar os dados.

Seu visor deve ter esta aparência.

Captura de tela de dados de exemplo depois de aplicar a opção de zoom shpwing grafo com VirtualAlloc Commit LifeTimes e Outstanding Commit by Process

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.

  1. Classifique afetando o tamanho clicando no cabeçalho da coluna.

  2. Expanda a linhaMemoryTestApp.exe (na coluna Processo ).

  3. Expanda a linha Impacting (na coluna Tipo de Impacto ).

  4. Navegue pelo processo Pilha de Confirmação até encontrar a função que alocou 10 MB de memória.

    Captura de tela da tabela de dados de exemplo mostrando Número de linha, processo, tipo de impacto, pilha de confirmação, tempo de confirmação, tempo de confirmação, contagem e tamanho de impacto

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.

Screenhsot do menu unzoom.

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.

Captura de tela do grafo mostrando dados de uso de memória.

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.

Captura de tela da opção de zoom.

Seu visor deve ter esta aparência:

Captura de tela do grafo mostrando dados de uso de memória usando a opção zoom.

  1. Classifique por Tamanho clicando no cabeçalho da coluna.

  2. Expanda a linhaMemoryTestApp.exe (na coluna Processo ).

  3. 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.
  4. Observe o valor das diferentes colunas:

    1. Contagem = 4: isso indica que quatro alocações transitórias de memória foram feitas durante esse intervalo de tempo.

    2. 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.

    3. 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.

  5. Navegue pelo processo Confirmar Pilha até encontrar as funções que alocaram 40 MB de memória.

    Captura de tela dos dados de uso 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

  1. Localize o grafo Alocações de Heap na categoria Memória do Explorer do Graph.

  2. Arraste e solte as Alocações de Heap na guia Análise .

  3. Organize a tabela para mostrar estas colunas:

    1. Processo

    2. Handle

    3. Tipo de impacto

    4. Pilha

    5. AllocTime

    6. Count

    7. Afetando tamanho e tamanho

  4. LocalizeMemoryTestApp.exe na lista de processos.

  5. 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:

Captura de tela de dados de exemplo mostrando o grafo Alocações de Heap de Tamanho Pendente por Processo e Identificador

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.

  1. Amplie um intervalo menor (por exemplo, 10 segundos) no meio do rastreamento.

  2. Expanda o identificador de cabeçalho que mostra a maior quantidade de alocações (conforme mostrado na coluna Tamanho impactando ).

  3. Expanda o tipo impactando .

  4. Navegue pelo processo Pilha até encontrar a função responsável por alocar toda essa memória.

    Captura de tela da tabela de dados de exemplo mostrando Process, Handle, Impacting Type, Stack, AllocTime, Count, Impacting Size e Size com duas linhas selecionadas

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