Compartilhar via


Usando UMDH para localizar um vazamento de memória User-Mode

O utilitário UMDH (heap de despejo de modo de usuário) funciona com o sistema operacional para analisar as alocações de heap do Windows para um processo específico. O UMDH localiza qual rotina em um processo específico está vazando memória.

O UMDH está incluído nas Ferramentas de Depuração para Windows. Para obter detalhes completos, consulte UMDH.

Preparando-se para usar UMDH

Se você ainda não determinou qual processo está vazando memória, faça isso primeiro. Para obter detalhes, consulte Usando Monitor de Desempenho para localizar vazamentos de memória User-Mode.

Os dados mais importantes nos logs UMDH são os rastreamentos de pilha das alocações de heap. Para determinar se um processo está vazando memória de heap, analise esses rastreamentos de pilha.

Antes de usar UMDH para exibir os dados de rastreamento de pilha, você deve usar GFlags para configurar seu sistema corretamente. O GFlags está incluído nas Ferramentas de Depuração para Windows.

As seguintes configurações de GFlags habilitam rastreamentos de pilha UMDH:

  • Na interface gráfica GFlags, escolha a guia Arquivo de Imagem, digite o nome do processo (incluindo a extensão de nome de arquivo), pressione a tecla TAB, selecione Criar banco de dados de rastreamento de pilha do modo de usuário e selecione Aplicar.

    Ou, equivalentemente, use a seguinte linha de comando GFlags, em que ImageName é o nome do processo (incluindo a extensão de nome de arquivo):

    gflags /i ImageName +ust 
    

    Use este comando para limpar as configurações de GFlag quando terminar. Para obter mais informações, consulte Comandos GFlags.

    gflags /i ImageName -ust 
    
  • Por padrão, a quantidade de dados de rastreamento de pilha que o Windows coleta é limitada a 32 MB em um processador x86 e 64 MB em um processador x64. Se você precisar aumentar o tamanho desse banco de dados, escolha a guia Arquivo de Imagem na interface gráfica GFlags, digite o nome do processo, pressione a tecla TAB marcar caixa de marcar Stack Backtrace (Megs), digite um valor (em MB) na caixa de texto associada e selecione Aplicar. Aumente esse banco de dados somente quando necessário, pois ele pode esgotar recursos limitados do Windows. Quando você não precisar mais do tamanho maior, retorne essa configuração ao seu valor original.

  • Se você alterou os sinalizadores na guia Registro do Sistema , reinicie o Windows para tornar essas alterações efetivas. Se você alterou os sinalizadores na guia Arquivo de Imagem , reinicie o processo para tornar as alterações efetivas. As alterações na guia Sinalizadores de Kernel entrarão em vigor imediatamente, mas serão perdidas na próxima vez que o Windows for reiniciado.

Antes de usar UMDH, você deve ter acesso aos símbolos adequados para seu aplicativo. UMDH usa o caminho do símbolo especificado pela variável de ambiente _NT_SYMBOL_PATH. Defina essa variável como igual a um caminho que contém os símbolos do aplicativo. Se você também incluir um caminho para símbolos do Windows, a análise poderá ser mais completa. A sintaxe desse caminho de símbolo é a mesma usada pelo depurador; para obter detalhes, consulte Caminho do símbolo.

Por exemplo, se os símbolos do seu aplicativo estiverem localizados em C:\MySymbols e você quiser usar o repositório de símbolos público da Microsoft para seus símbolos do Windows, usando C:\MyCache como seu repositório downstream, você usaria o seguinte comando para definir o caminho do símbolo:

set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*https://msdl.microsoft.com/download/symbols 

Além disso, para garantir resultados precisos, você deve desabilitar o cache BSTR. Para fazer isso, defina a variável de ambiente OANOCACHE igual a uma (1). Faça essa configuração antes de iniciar o aplicativo cujas alocações devem ser rastreadas.

Se precisar rastrear as alocações feitas por um serviço, defina OANOCACHE como uma variável de ambiente do sistema e reinicie o Windows para que essa configuração entre em vigor.

Detectando aumentos nas alocações de heap com UMDH

Depois de fazer essas preparações, você pode usar UMDH para capturar informações sobre as alocações de heap de um processo. Para fazer isso, siga este procedimento:

  1. Determine a ID do processo (PID) para o processo que você deseja investigar.

  2. Use UMDH para analisar as alocações de memória de heap para esse processo e salvá-lo em um arquivo de log. Use a opção -p com o PID e a opção -f com o nome do arquivo de log. Por exemplo, se o PID for 124 e você quiser nomear o arquivo de log Log1.txt, use o seguinte comando:

    umdh -p:124 -f:log1.txt 
    
  3. Use o Bloco de Notas ou outro programa para abrir o arquivo de log. Esse arquivo contém a pilha de chamadas para cada alocação de heap, o número de alocações feitas por meio dessa pilha de chamadas e o número de bytes consumidos por meio dessa pilha de chamadas.

  4. Como você está procurando um vazamento de memória, o conteúdo de um único arquivo de log não é suficiente. Você deve comparar arquivos de log registrados em momentos diferentes para determinar quais alocações estão crescendo.

    O UMDH pode comparar dois arquivos de log diferentes e exibir a alteração em seus respectivos tamanhos de alocação. Você pode usar o símbolo maior que (>) para redirecionar os resultados para um terceiro arquivo de texto. Talvez você também queira incluir a opção -d, que converte as contagens de bytes e alocação de hexadecimal em decimal. Por exemplo, para comparar Log1.txt e Log2.txt, salvando os resultados da comparação com o arquivo LogCompare.txt, use o seguinte comando:

    umdh log1.txt log2.txt > logcompare.txt 
    
  5. Abra o arquivo LogCompare.txt. Seu conteúdo é semelhante ao seguinte:

    + 5320 ( f110 - 9df0) 3a allocs BackTrace00B53 
    Total increase == 5320 
    

    Para cada pilha de chamadas (rotulada como "BackTrace") nos arquivos de log UMDH, há uma comparação entre os dois arquivos de log. Neste exemplo, o primeiro arquivo de log (Log1.txt) registrou 0x9DF0 bytes alocados para BackTrace00B53, enquanto o segundo arquivo de log registrou 0xF110 bytes, o que significa que havia 0x5320 bytes adicionais alocados entre o momento em que os dois logs foram capturados. Os bytes vieram da pilha de chamadas identificada por BackTrace00B53.

  6. Para determinar o que está nesse backtrace, abra um dos arquivos de log originais (por exemplo, Log2.txt) e pesquise "BackTrace00B53". Os resultados são semelhantes a esses dados:

    00005320 bytes in 0x14 allocations (@ 0x00000428) by: BackTrace00B53
    ntdll!RtlDebugAllocateHeap+0x000000FD
    ntdll!RtlAllocateHeapSlowly+0x0000005A
    ntdll!RtlAllocateHeap+0x00000808
    MyApp!_heap_alloc_base+0x00000069
    MyApp!_heap_alloc_dbg+0x000001A2
    MyApp!_nh_malloc_dbg+0x00000023
    MyApp!_nh_malloc+0x00000016
    MyApp!operator new+0x0000000E
    MyApp!DisplayMyGraphics+0x0000001E
    MyApp!main+0x0000002C
    MyApp!mainCRTStartup+0x000000FC
    KERNEL32!BaseProcessStart+0x0000003D 
    

    Essa saída UMDH mostra que houve 0x5320 (decimal 21280) total de bytes alocados da pilha de chamadas. Esses bytes foram alocados de 0x14 (decimal 20) alocações separadas de 0x428 (decimal 1064) bytes cada.

    A pilha de chamadas recebe um identificador de "BackTrace00B53" e as chamadas nessa pilha são exibidas. Ao revisar a pilha de chamadas, você verá que a rotina DisplayMyGraphics está alocando memória por meio do novo operador, que chama o malloc de rotina, que usa a biblioteca de tempo de execução do Visual C++ para obter memória do heap.

    Determine qual dessas chamadas é a última a aparecer explicitamente no código-fonte. Nesse caso, provavelmente é o novo operador porque a chamada para malloc ocorreu como parte da implementação de new e não como uma alocação separada. Portanto, essa instância do novo operador na rotina DisplayMyGraphics está alocando repetidamente memória que não está sendo liberada.