Compartilhar via


Análise de despejo de memória

Nem todos os bugs podem ser encontrados antes do lançamento, o que significa que nem todos os bugs que geram exceções podem ser encontrados antes do lançamento. Felizmente, a Microsoft incluiu no SDK da plataforma uma função para ajudar os desenvolvedores a coletar informações sobre exceções descobertas pelos usuários. A função MiniDumpWriteDump grava as informações necessárias do despejo de falhas em um arquivo sem salvar todo o espaço do processo. Esse arquivo de informações de despejo de falhas é chamado de minidespejo. Este artigo técnico fornece informações sobre como escrever e usar um minidespejo.

Escrever um minidespejo

As opções básicas para escrever um minidespejo são as seguintes:

  • Não fazer nada. O Windows gera automaticamente um minidespejo sempre que um programa gera uma exceção sem tratamento. A geração automática de um minidespejo está disponível desde o Windows XP. Se o usuário permitir, o minidespejo será enviado para a Microsoft, e não para o desenvolvedor, por meio do Relatório de Erros do Windows (WER). Os desenvolvedores podem obter acesso a esses minidespejos por meio do Programa de aplicativos da área de trabalho do Windows.

    O uso do WER requer:

    • Desenvolvedores para assinar seus aplicativos usando o Authenticode
    • Os aplicativos têm um recurso VERSIONINFO válido em cada executável e DLL

    Se você implementar uma rotina personalizada para exceções sem tratamento, é altamente recomendável usar a função ReportFault no manipulador de exceções para também enviar um minidespejo automatizado para o WER. A função ReportFault lida com todos os problemas de conexão e envio do minidespejo para o WER. Não enviar minidespejos para o WER viola os requisitos do Games for Windows.

    Para obter mais informações sobre o WER, consulte Relatório de erros do Windows.

  • Use um produto do Microsoft Visual Studio Team System. No menu Depurar, clique em Salvar despejo como para salvar uma cópia de um despejo. O uso de um despejo salvo localmente é apenas uma opção para teste e depuração internos.

  • Adicione código ao seu projeto. Adicione a função MiniDumpWriteDump e o código de tratamento de exceção apropriado para salvar e enviar um minidespejo diretamente ao desenvolvedor. Este artigo demonstra como implementar essa opção. No entanto, observe que MiniDumpWriteDump atualmente não funciona com código gerenciado e só está disponível no Windows XP, Windows Vista e Windows 7.

Acesso thread-safe

MiniDumpWriteDump faz parte da biblioteca DBGHELP. Essa biblioteca não é thread-safe, portanto, qualquer programa que use MiniDumpWriteDump deve sincronizar todos os threads antes de tentar chamar MiniDumpWriteDump.

Escrever um minidespejo com código

A implementação real é simples. Veja a seguir um exemplo simples de como usar MiniDumpWriteDump.

#include <dbghelp.h>
#include <shellapi.h>
#include <shlobj.h>

int GenerateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH]; 
    WCHAR szFileName[MAX_PATH]; 
    WCHAR* szAppName = L"AppName";
    WCHAR* szVersion = L"v1.0";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPath( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectory( szFileName, NULL );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp", 
               szPath, szAppName, szVersion, 
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, 
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond, 
               GetCurrentProcessId(), GetCurrentThreadId());
    hDumpFile = CreateFile(szFileName, GENERIC_READ|GENERIC_WRITE, 
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), 
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);

    return EXCEPTION_EXECUTE_HANDLER;
}


void SomeFunction()
{
    __try
    {
        int *pBadPtr = NULL;
        *pBadPtr = 0;
    }
    __except(GenerateDump(GetExceptionInformation()))
    {
    }
}

Este exemplo demonstra o uso básico de MiniDumpWriteDump e as informações mínimas necessárias para chamá-lo. O nome do arquivo de despejo depende do desenvolvedor. No entanto, para evitar colisões de nome de arquivo, é aconselhável gerá-lo a partir do nome e do número da versão do aplicativo, das IDs de processo, das thread, da data e da hora. Isso também ajudará a manter os minidespejos agrupados por aplicativo e versão. Cabe ao desenvolvedor decidir a quantidade de informação que é usada para diferenciar os nomes de arquivos de minidespejo.

Deve-se observar que o nome do caminho no exemplo anterior foi gerado chamando a função GetTempPath para recuperar o caminho do diretório designado para arquivos temporários. O uso desse diretório funciona mesmo com contas de usuário com menos privilégios e também evita que o minidespejo ocupe espaço no disco rígido depois de não ser mais necessário.

Se você arquivar o produto durante o processo diário de compilação, certifique-se também de incluir símbolos, de modo que possa depurar uma versão antiga do produto, se necessário. Você também precisa tomar medidas para manter as otimizações completas do compilador ao gerar símbolos. Isso pode ser feito abrindo as propriedades do seu projeto no ambiente de desenvolvimento e, para a configuração de versão, faça o seguinte:

  1. No lado esquerdo da página de propriedades do projeto, clique em C/C++. Por padrão, isso exibe as configurações Gerais. No lado direito da página de propriedades do projeto, defina o Formato de informações de depuração como Banco de dados do programa (/Zi).
  2. No lado esquerdo da página de propriedades, expanda Vinculador e clique em Depuração. No lado direito da página de propriedades, defina Gerar informações de depuração como Sim (/DEBUG).
  3. Clique em Otimização e defina Referências como Eliminar dados não referenciados (/OPT:REF).
  4. Defina Habilitar dobramento COMDAT para Remover COMDATs redundantes (/OPT:ICF).

Para obter mais informações, consulte a estrutura MINIDUMP_EXCEPTION_INFORMATION e a função MiniDumpWriteDump.

Usar Dumpchk.exe

Dumpchk.exe é um utilitário de linha de comando que pode ser usado para verificar se um arquivo de despejo foi criado de forma correta. Se Dumpchk.exe gerar um erro, isso significará que o arquivo de despejo está corrompido e não pode ser analisado. Para obter informações sobre como usar o Dumpchk.exe, consulte Como usar o Dumpchk.exe para verificar um arquivo de despejo de memória.

Dumpchk.exe está incluído no CD do produto Windows XP e pode ser instalado na Unidade do Sistema\Arquivos de Programas\Ferramentas de Suporte\ executando Setup.exe na pasta Suporte\Ferramentas\ no CD do produto Windows XP. Você também pode obter a versão mais recente do Dumpchk.exe baixando e instalando as ferramentas de depuração disponíveis em Ferramentas de depuração do Windows na Central do desenvolvedor de hardware do Windows.

Analisar um minidespejo

Abrir um minidespejo para análise é tão fácil quanto criar um.

Para analisar um minidespejo

  1. Abra o Visual Studio.
  2. No menu Arquivo, clique em Abrir projeto.
  3. Defina Arquivos do tipo como Arquivos de despejo, navegue até o arquivo de despejo, selecione-o e clique em Abrir.
  4. Execute o depurador.

O depurador criará um processo simulado. O processo simulado será interrompido na instrução que causou a falha.

Usar o servidor de símbolos públicos da Microsoft

Para obter a pilha para falhas no nível do driver ou do sistema, pode ser necessário configurar o Visual Studio para apontar para o servidor de símbolos público da Microsoft.

Para definir um caminho para o servidor de símbolos da Microsoft

  1. No menu Depurar, clique em Opções.
  2. Na caixa de diálogo Opções abra o nó Depuração e clique em Símbolos.
  3. Certifique-se de Pesquisar os locais acima somente quando os símbolos forem carregados manualmente, a menos que você queira carregar os símbolos manualmente ao depurar.
  4. Se estiver usando símbolos em um servidor de símbolos remoto, será possível melhorar o desempenho especificando um diretório local para o qual os símbolos possam ser copiados. Para fazer isso, insira um caminho para Armazenar em cache os símbolos do servidor de símbolos nesse diretório. Para se conectar ao servidor de símbolos públicos da Microsoft, você precisa habilitar essa configuração. Observe que, se estiver depurando um programa em um computador remoto, o diretório de cache se refere a um diretório no computador remoto.
  5. Clique em OK.
  6. Como você está usando o servidor de símbolos públicos da Microsoft, será exibida uma caixa de diálogo sobre contrato de licença do usuário final. Clique em Sim para aceitar o contrato e baixar símbolos para o cache local.

Depurar um minidespejo com o WinDbg

Você também pode usar o WinDbg, um depurador que faz parte das ferramentas de depuração do Windows, para depurar um minidespejo. O WinDbg permite que você depure sem precisar usar o Visual Studio. Para baixar as ferramentas de depuração do Windows, consulte Ferramentas de depuração do Windows na Central do desenvolvedor de hardware do Windows.

Depois de instalar as ferramentas de depuração do Windows, você deve inserir o caminho do símbolo no WinDbg.

Para inserir um caminho de símbolo no WinDbg

  1. No menu de Arquivo clique em Caminho do símbolo.

  2. Na janela Caminho de pesquisa de símbolos digite o seguinte:

    "srv\*c:\\cache\*https://msdl.microsoft.com/download/symbols;"

Usar ferramentas de proteção contra cópia com minidespejos

Os desenvolvedores também precisam estar cientes de como seu esquema de proteção contra cópia pode afetar o minidespejo. A maioria dos esquemas de proteção contra cópia tem suas próprias ferramentas de decodificação, e cabe ao desenvolvedor aprender a usar essas ferramentas com MiniDumpWriteDump..

Resumo

A função MiniDumpWriteDump pode ser uma ferramenta extremamente útil na coleta e resolução de bugs após o lançamento do produto. Gravar um manipulador de exceção personalizado que usa MiniDumpWriteDump permite que o desenvolvedor personalize a coleta de informações e melhore o processo de depuração. A função é flexível o suficiente para ser usada em qualquer projeto baseado em C++ e deve ser considerada parte do processo de estabilidade de qualquer projeto.