Rastreamento de solicitações de alocação de Heap
This topic applies to:
Edition |
Visual Basic |
C# |
F# |
C++ |
Web Developer |
---|---|---|---|---|---|
Express |
Native only |
||||
Pro, Premium e Ultimate |
Native only |
Embora identificando o número origem de linha e o nome de arquivo em que o executa um assert ou o relatório de macro geralmente é muito útil para localizar a causa do problema, o mesmo não é mais provável de serem verdadeiras das funções de alocação de heap. Enquanto as macros podem ser inseridas em muitos pontos apropriados na árvore de lógica do aplicativo, uma alocação freqüentemente é incluída em uma rotina especial que é chamada a partir de muitos locais diferentes em vários momentos diferentes. A pergunta é geralmente não qual linha de código feita uma alocação incorreta, mas em vez disso, o qual uma das milhares de alocações feitas por essa linha de código foi incorreto e por quê.
_CrtBreakAlloc e números exclusivos de solicitação de alocação
A maneira mais simples para identificar a chamada de alocação de heap específicos que ficou ruim é aproveitar o número de solicitação de alocação exclusivo associado a cada bloco na pilha de depuração. Quando as informações sobre um bloco são relatadas por uma das funções de despejo, esse número de solicitação de alocação é entre chaves (por exemplo, "{36}").
Quando você souber o número de solicitação de alocação de um bloco reservado incorretamente, você pode passar esse número para _CrtSetBreakAlloc para criar um ponto de interrupção. A execução interromperá antes de alocar o bloco e você pode refazer o caminho para determinar qual rotina era responsável pela chamada incorreta. Para evitar a recompilação, você pode realizar a mesma coisa no depurador definindo _crtBreakAlloc para o número de solicitação de alocação que você está interessado.
Criação de versões de depuração de suas rotinas de alocação
Uma abordagem um pouco mais complicada é criar versões de depuração de suas próprias rotinas de alocação, comparáveis da _dbg versões da funções de alocação de heap. Depois poderá passar o arquivo de origem e de linha por meio de argumentos de número para as rotinas de alocação de heap subjacente, e você poderá imediatamente ver onde foi originada de uma alocação incorreta.
Por exemplo, suponha que seu aplicativo contém uma rotina comumente usada semelhante à seguinte:
int addNewRecord(struct RecStruct * prevRecord,
int recType, int recAccess)
{
// ...code omitted through actual allocation...
if ((newRec = malloc(recSize)) == NULL)
// ... rest of routine omitted too ...
}
Em um arquivo de cabeçalho, você poderia adicionar código como, por exemplo, o seguinte:
#ifdef _DEBUG
#define addNewRecord(p, t, a) \
addNewRecord(p, t, a, __FILE__, __LINE__)
#endif
Em seguida, você poderia alterar a alocação em sua rotina de criação de registros da seguinte maneira:
int addNewRecord(struct RecStruct *prevRecord,
int recType, int recAccess
#ifdef _DEBUG
, const char *srcFile, int srcLine
#endif
)
{
/* ... code omitted through actual allocation ... */
if ((newRec = _malloc_dbg(recSize, _NORMAL_BLOCK,
srcFile, scrLine)) == NULL)
/* ... rest of routine omitted too ... */
}
Agora o arquivo de origem nome e a linha número onde addNewRecord foi chamado serão armazenadas em cada bloco resultante alocado na pilha de depuração e será reportado quando desse bloco é examinado.