MFC Debugging Techniques

Se você está depurando um programa MFC, essas técnicas de depuração podem ser úteis.

Neste tópico

AfxDebugBreak

A macro trace

Detectando vazamentos de memória em MFC

  • As alocações de memória de rastreamento

  • Ativando diagnóstico de memória

  • Otendo instantâneos de memória

  • Estatísticas de memória de exibição

  • Colocando despejos de objeto

    • Interpretando despejos de memória

    • Personalizando despejos de objeto

    Reduzindo o tamanho de uma construção de depuração MFC

    • Criando um aplicativo MFC com informações de depuração para módulos selecionados

AfxDebugBreak

O MFC fornece uma função especial de AfxDebugBreak para pontos de interrupção de embutir no código-fonte:

AfxDebugBreak( );

Em plataformas Intel, AfxDebugBreak gera o código a seguir, que interrompe no código-fonte em vez do código kernel:

_asm int 3

Em outras plataformas, AfxDebugBreak chama simplesmente DebugBreak.

Certifique-se de remova instruções de AfxDebugBreak quando você cria uma compilação de versão ou usa #ifdef _DEBUG para colocar as.

Neste tópico

A macro trace

Para exibir mensagens do seu programa no depurador A janela de saída, você pode usar a macro de ATLTRACE ou a macro MFC RASTREAMENTO .Como asserções, macros de rastreamento são ativos somente na versão de depuração do seu programa e desaparecem quando criados na versão de lançamento.

Aos exemplos a seguir mostram algumas das maneiras você pode usar a macro de RASTREAR .Como printf, a macro de RASTREAR pode manipular um número de argumentos.

int x = 1;
int y = 16;
float z = 32.0;
TRACE( "This is a TRACE statement\n" );

TRACE( "The value of x is %d\n", x );

TRACE( "x = %d and y = %d\n", x, y );

TRACE( "x = %d and y = %x and z = %f\n", x, y, z );

A macro trace trata adequadamente parâmetros de char* e de wchar_t*.Os seguintes exemplos demonstram o uso de macro trace junto com diferentes tipos de parâmetros da cadeia de caracteres.

TRACE( "This is a test of the TRACE macro that uses an ANSI string: %s %d\n", "The number is:", 2);

TRACE( L"This is a test of the TRACE macro that uses a UNICODE string: %s %d\n", L"The number is:", 2);

TRACE( _T("This is a test of the TRACE macro that uses a TCHAR string: %s %d\n"), _T("The number is:"), 2);

Para obter mais informações sobre o macro de RASTREAR , consulte Serviços diagnóstico.

Neste tópico

Detectando vazamentos de memória em MFC

O MFC fornece classes e funções para detectar a memória que é atribuída mas nunca desalocada.

7sx52ww7.collapse_all(pt-br,VS.110).gifAs alocações de memória de rastreamento

No MFC, você pode usar DEBUG_NEW macro no lugar do operador de new para ajudar a localizar vazamentos de memória.Na versão de depuração do seu programa, DEBUG_NEW mantém registro de nome de arquivo e número da linha para cada objeto que atribui.Quando você cria uma versão de lançamento do seu programa, DEBUG_NEW resolve a new uma operação simples sem o nome de arquivo e a linha informações de número.Portanto, não paga nenhuma penalidade de velocidade na versão de lançamento do seu programa.

Se você não desejar reescrever o seu programa inteiro para usar DEBUG_NEW no lugar de new, você pode definir esse macro em seus arquivos de origem:

#define new DEBUG_NEW

Quando você faz despejo de objeto, cada objeto atribuído com DEBUG_NEW mostrará o arquivo e o número da linha onde ele foi atribuído, permitindo que você localizar as fontes de vazamentos de memória.

A versão de depuração de estrutura MFC usa DEBUG_NEW automaticamente, mas seu código não.Se você deseja que os benefícios de DEBUG_NEW, você deve usar DEBUG_NEW ou explicitamente #define new como mostrado acima.

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifAtivando diagnóstico de memória

Antes que você possa usar recursos de diagnósticos de memória, você deve ativar o rastreamento diagnóstico.

Para ativar ou desativar diagnóstico de memória

  • Chamar a função global AfxEnableMemoryTracking para ativar ou desativar o distribuidor diagnóstico de memória.Porque diagnósticos de memória está ativada por padrão na biblioteca de depuração, você geralmente usará essa função para desligá-los temporariamente, o que aumenta a velocidade de execução do programa e reduz saída de diagnóstico.

Para selecionar recursos específicos de diagnóstico memória com afxMemDF

  • Se você quiser um controle mais preciso sobre os recursos de diagnósticos memória, você pode desativar seletivamente recursos individuais de diagnóstico sobre memória e definir o valor da variável global afxMemDFMFC.Esta variável pode ter os seguintes valores como especificados pelo tipo enumerado afxMemDF.

    Valor

    Descrição

    allocMemDF

    Ativar o distribuidor diagnóstico de memória (padrão).

    delayFreeMemDF

    Atrasar liberar memória para chamar delete ou até free saída de programa.Isso fará com que seu programa atribua a quantidade de memória máximo possível.

    checkAlwaysMemDF

    Chamar AfxCheckMemory sempre que a memória é liberada ou atribuída.

    Esses valores podem ser usados em combinação executando uma operação OR lógica, como mostrado aqui:

    afxMemDF = allocMemDF | delayFreeMemDF | checkAlwaysMemDF;
    

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifOtendo instantâneos de memória

  1. Crie um objeto de CMemoryState e chamar a função de membro de CMemoryState::Checkpoint .Isso cria o primeiro instantâneo de memória.

  2. Depois que o programa executa as operações de alocação de memória e de desalocação, crie outro objeto de CMemoryState e chamar Checkpoint para esse objeto.Isso é um segundo instantâneo de uso de memória.

  3. Crie um objeto de CMemoryState do terceiro e chamar a função de membro do CMemoryState::Difference , fornecendo como argumentos os dois objetos anteriores de CMemoryState .Se há uma diferença entre os dois estados de memória, a função de Difference retorna um valor diferente de zero.Isso indica que alguns blocos de memória não foram desalocados.

    Este exemplo mostra como o código parece:

    // Declare the variables needed
    #ifdef _DEBUG
        CMemoryState oldMemState, newMemState, diffMemState;
        oldMemState.Checkpoint();
    #endif
    
        // Do your memory allocations and deallocations.
        CString s("This is a frame variable");
        // The next object is a heap object.
       CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
    
    #ifdef _DEBUG
        newMemState.Checkpoint();
        if( diffMemState.Difference( oldMemState, newMemState ) )
        {
            TRACE( "Memory leaked!\n" );
        }
    #endif
    

    Observe que as instruções memória verificando são suportados por #ifdefDEBUG/blocos de #endif de modo que sejam compiladas somente em versões de depuração do seu programa.

    Agora que você sabe um vazamento de memória existir, você pode usar outra função de membro, CMemoryState::DumpStatistics, a Visualização de estatística de memória que ajudarão você a localizar.

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifEstatísticas de memória de exibição

A função de CMemoryState::Difference tem dois objetos de memória estado e detecta todos os objetos não desalocados da heap entre o início e os estados de extremidade.Depois que você recebe instantâneos de memória e os comparou que usam CMemoryState::Difference, você pode chamar CMemoryState::DumpStatistics para obter informações sobre objetos que não foram desalocados.

Considere o exemplo a seguir:

if( diffMemState.Difference( oldMemState, newMemState ) )
{
   TRACE( "Memory leaked!\n" );
   diffMemState.DumpStatistics();
}

Um despejo de exemplo de exemplo tem esta aparência:

0 bytes in 0 Free Blocks
22 bytes in 1 Object Blocks
45 bytes in 4 Non-Object Blocks
Largest number used: 67 bytes
Total allocations: 67 bytes

Blocos livres são os blocos cuja desalocação é tardia se afxMemDF foi definido como delayFreeMemDF.

Blocos comuns de objeto, mostrados na segunda linha, permanecem atribuídos no heap.

Blocos de objeto não incluem matrizes e estruturas atribuídas com new.Nesse caso, quatro blocos de objeto não foram atribuídos no heap mas não desalocados.

Largest number used fornece a memória máximo usada pelo programa a qualquer momento.

Total allocations fornece a quantidade total de memória usada pelo programa.

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifColocando despejos de objeto

Em um programa MFC, você pode usar CMemoryState::DumpAllObjectsSince para despejar uma descrição de todos os objetos na heap que não foram desalocados.DumpAllObjectsSince despeja todos os objetos atribuídos desde que CMemoryState::Checkpointo último.Se nenhuma chamada de Checkpoint ocorreu, DumpAllObjectsSince despeja todos os objetos e nonobjects na memória.

ObservaçãoObservação

Antes que você possa usar o objeto MFC que despeja, você deve ativar o rastreamento diagnóstico.

ObservaçãoObservação

O MFC despeja automaticamente todos os objetos de escape quando a saída do programa, então você não precisará criar o código para despejar nesse ponto objetos.

Os seguintes teste de código para um vazamento de memória comparando dois estados e despejos de memória todos os objetos se um escape for detectado.

if( diffMemState.Difference( oldMemState, newMemState ) )
{
   TRACE( "Memory leaked!\n" );
   diffMemState.DumpAllObjectsSince();
}

O conteúdo de despejo se parecem com o seguinte:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

Números em chaves no início de linhas especificam a ordem em que os objetos foram atribuídos.O objeto recentemente atribuído tem o número mais alto e aparece na parte superior de despejo.

Para obter a quantidade de informações máximo fora de um despejo de objeto, você pode substituir a função de membro de qualquer CObjectobjeto derivado de t:system.windows.documents.block de Dump para personalizar o despejo de objeto.

Você pode definir um ponto de interrupção em uma alocação de memória específico definir a variável global _afxBreakAlloc para o número mostrado em chaves.Se você executar o programa novamente o depurador interromperá a execução quando essa alocação ocorre.Você pode então examinar a pilha de chamadas para ver como seu programa obtido a esse ponto.

A biblioteca em tempo de execução de C tem uma função semelhante, _CrtSetBreakAlloc, que você pode usar para as alocações de tempo de execução de C.

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifInterpretando despejos de memória

Se este despejo de objeto com mais detalhes:

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

O programa que gerou este despejo tivesse apenas duas alocações - um explícitas em uma pilha e no heap:

// Do your memory allocations and deallocations.
CString s("This is a frame variable");
// The next object is a heap object.
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );

O construtor de CPerson utiliza três argumentos que são ponteiros a char, que são usados para inicializar variáveis de membro de CString .Em despejo de memória, você pode ver o objeto de CPerson junto com três blocos de nonobject (3, 4, e 5).Esses contêm os caracteres para as variáveis de membro de CString e não serão excluídos enquanto o destrutor do objeto de CPerson é chamado.

O bloco número 2 é o próprio objeto de CPerson .$51A4 representa o endereço do bloco e é seguido pelo conteúdo do objeto, que eram saída pelo ::Dump de CPersonquando chamados por DumpAllObjectsSince.

Você pode descobrir que o bloco número 1 está associado com a variável quadro de CString devido seus número e tamanho de sequência, que corresponde ao número de caracteres na variável de CString do quadro.Variáveis atribuídos no quadro são desalocados automaticamente quando o quadro sai do escopo.

Variáveis de quadro chave

Geralmente, você não precisa se preocupar com objetos de heap associados com variáveis do quadro porque eles são desalocados automaticamente quando variáveis do quadro sai do escopo.Para evitar a confusão em seus despejos de diagnóstico de memória, você deve posicionar seus chamadas a Checkpoint de modo que eles fiquem fora do escopo de variáveis do quadro.Por exemplo, colchetes o escopo do local em torno do código anterior de alocação, como mostrado aqui:

oldMemState.Checkpoint();
{
    // Do your memory allocations and deallocations ...
    CString s("This is a frame variable");
    // The next object is a heap object.
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
}
newMemState.Checkpoint();

Com os colchetes de escopo no lugar, o despejo de memória para esse exemplo é a seguinte:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

As alocações de Nonobject

Observe que algumas alocações são objetos (como CPerson) e alguns são alocações de nonobject. “As alocações de Nonobject” são alocações para os objetos não derivados de CObject ou alocações de c# primitivos como char, int, ou long.Se a classe derivada de CObject-atribui o espaço extra, como para buffers internos, esses objetos mostrará alocações de objeto e de nonobject.

Evitando vazamentos de memória

O aviso no código acima de que o bloco de memória associado com a variável quadro de CString foi desalocado automaticamente e não aparece como um vazamento de memória.A desalocação automático associada com as regras de escopo leva de vazamentos de memória associados com variáveis do quadro.

Para os objetos atribuídos no heap, no entanto, você deve explicitamente excluir o objeto para evitar um vazamento de memória.Para limpar o vazamento de memória o último no exemplo anterior, exclua o objeto de CPerson atribuído no heap, como segue:

{
    // Do your memory allocations and deallocations.
    CString s("This is a frame variable");
    // The next object is a heap object.
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
    delete p;
}

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifPersonalizando despejos de objeto

Quando você deriva de uma classe CObject, você pode substituir a função de membro de Dump para fornecer informações adicionais quando você usa DumpAllObjectsSince para despejar objetos A janela de saída.

A função de Dump grava uma representação textual das variáveis de membro de objeto em um contexto de despejo (CDumpContext).O contexto de despejo é semelhante a um fluxo de E/S.Você pode usar o operador acrescentar (<<) para enviar dados a CDumpContext.

Quando você substituir a função de Dump , você deve primeiro chamar a versão da classe base de Dump despejar o conteúdo do objeto da classe base.Saída em uma descrição textual e um valor para cada variável de membro da classe derivada.

A declaração de função de Dump tem esta aparência:

class CPerson : public CObject
{
public:
#ifdef _DEBUG
    virtual void Dump( CDumpContext& dc ) const;
#endif

    CString m_firstName;
    CString m_lastName;
    // And so on...
};

Porque o objeto que despeja somente faz sentido quando você está depurando seu programa, a declaração de função de Dump é suportada com um bloco de #ifdef _DEBUG / #endif .

No exemplo a seguir, chamadas de função de Dump os primeiros a função de Dump para sua classe base.Grava uma breve descrição de cada variável de membro juntamente com o valor do membro para o fluxo diagnóstico.

#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
    // Call the base class function first.
    CObject::Dump( dc );

    // Now do the stuff for our specific class.
    dc << "last name: " << m_lastName << "\n"
        << "first name: " << m_firstName << "\n";
}
#endif

Você deve fornecer um argumento de CDumpContext para especificar onde a saída de despejo irã0.A versão de depuração do MFC fornece CDumpContext predefinido afxDump chamado objeto que envia saída para o depurador.

CPerson* pMyPerson = new CPerson;
// Set some fields of the CPerson object.
//...
// Now dump the contents.
#ifdef _DEBUG
pMyPerson->Dump( afxDump );
#endif

Neste tópico

Reduzindo o tamanho de uma construção de depuração MFC

Informações de depuração para um grande aplicativo MFC pode pegar muito espaço em disco.Você pode usar um desses procedimentos para reduzir o tamanho:

  1. Crie as bibliotecas MFC usando a opção de / /Z7, /Zi, /ZI (formato informações de depuração) , em vez de /Z7.Essas opções criar um único arquivo de (PDB) de banco de dados do programa que contém informações de depuração para a biblioteca inteira, reduzindo a redundância e salvando o espaço.

  2. Crie as bibliotecas MFC sem informações de depuração (nenhuma opção de / /Z7, /Zi, /ZI (formato informações de depuração) ).Nesse caso, a falta de informações de depuração impedirá que você use a maioria dos recursos do depurador no código de biblioteca MFC, mas como bibliotecas MFC já são completamente depuradas, isso pode não ser um problema.

  3. Criar seu próprio aplicativo com informações de depuração para módulos selecionados somente conforme descrito abaixo.

Neste tópico

7sx52ww7.collapse_all(pt-br,VS.110).gifCriando um aplicativo MFC com informações de depuração para módulos selecionados

Compilar módulos selecionados com bibliotecas de depuração MFC permite que você use pisando e outros recursos de depuração nesses módulos.Este procedimento usa os modos de depuração e versão de makefile do Visual C++, bem necessitando as alterações descritas nas seguintes etapas (e também fazendo uma recompilação “qualquer” necessária quando uma compilação completa de versão é necessária).

  1. No Solution Explorer, selecione o projeto.

  2. No menu de Modo de Visualização , Páginas de Propriedade.

  3. Primeiro, você criará uma nova configuração do projeto.

    1. Na caixa de diálogo <Project> Páginas de Propriedade , clique no botão de Gerenciador de Configurações .

    2. Em Caixa de diálogo Configuration Manager, localize seu projeto na grade.Na coluna de Configuração , selecione <New...>.

    3. Em A caixa de diálogo novo de configurações do projeto, digite um nome para a nova configuração, como “depuração parcial”, na caixa de Nome da configuração de Projeto .

    4. Na lista de Copiar configurações de , escolha Versão.

    5. Clique OK para fechar a caixa de diálogoNova Configuração de Projeto.

    6. Fechar a caixa de diálogo Gerenciador de Configurações .

  4. Agora, você irá definir opções para o projeto inteiro.

    1. Na caixa de diálogo Páginas de Propriedade , sob a pasta de Propriedades de Configuração , selecione a categoria de Geral .

    2. Na grade de configurações do projeto, expanda Padrões de Projeto (se necessário).

    3. Em Padrões de Projeto, localize Uso do MFC.A configuração atual aparece na coluna à direita da grade.Clique na configuração atual e altere-a para Usar MFC em uma Static Library.

    4. No painel esquerdo da caixa de diálogo Páginas de propriedades , abra a pasta de C/C++ e selecione Pré-Processador.Nas propriedades grade, localize Definições do Pré-processador e substitui “NDEBUG” com “_DEBUG”.

    5. No painel esquerdo da caixa de diálogo Páginas de propriedades , abra a pasta de Vinculador e selecione a categoria de Entrada .Na grade properties, localize Dependências Adicionais.Na configuração de Dependências Adicionais , em NAFXCWD.LIB tipo “e” em “LIBCMT”.

    6. Clique OK para salvar as novas opções de compilação e para fechar a caixa de diálogo Páginas de Propriedade .

  5. No menu de Compilar , Recompilar.Remove todas as informações de depuração dos módulos mas não afeta a biblioteca MFC.

  6. Agora você deve adicionar as informações de depuração de volta para módulos selecionados em seu aplicativo.Lembre-se de que você pode definir pontos de interrupção e executar outro depurador funciona somente em módulos que você criou com informações de depuração.Para cada arquivo de projeto em que você deseja incluir informações de depuração, realize as seguintes etapas:

    1. No solution Explorer, abra a pasta de Arquivos de Origem localizada sob o seu projeto.

    2. Selecione o arquivo que você deseja definir informações de depuração para.

    3. No menu de Modo de Visualização , Páginas de Propriedade.

    4. Na caixa de diálogo Páginas de Propriedade , sob a pasta de Parâmetros de configuração , abra a pasta de C/C++ então selecione a categoria de Geral .

    5. Na grade properties, localize Formato de Informação de Depuração.

    6. Clique nas configurações de Formato de Informação de Depuração e selecione a opção desejada (geralmente /ZI) para informações de depuração.

    7. Se você estiver usando um aplicativo assistentes gerado de aplicativo ou tiver cabeçalhos pré-compilados, você precisa desativar os cabeçalhos pré-compilados ou recompilar-los antes de criar os outros módulos.Caso contrário, você receberá C4650 de aviso e mensagem de erro C2855.Você pode desativar cabeçalhos pré-compilados alterando a configuração Criar/Usar cabeçalhos pré-compilados na caixa de diálogo <Project> Propriedades (pasta Propriedades de Configuração, subpasta C/C++, categoria Cabeçalhos Pré-Compilados).

  7. No menu de Compilar , selecione Compilar para reconstruir os arquivos de projeto que são expirado.

Como uma alternativa para a técnica descrita neste tópico, você pode usar um makefile externa para definir opções individuais para cada arquivo.Nesse caso, para vincular com bibliotecas de depuração MFC, você deve definir o sinalizador de _DEBUG para cada módulo.Se você desejar usar bibliotecas de versão MFC, você deve definir NDEBUG.Para obter mais informações sobre para gravar makefiles externos, consulte Referência de NMAKE.

Neste tópico

Consulte também

Outros recursos

Depuração Visual C++