65.9K
CodeProject 正在变化。 阅读更多。
Home

无需工具的内存泄漏检测程序

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.96/5 (21投票s)

2008 年 4 月 9 日

CPOL

2分钟阅读

viewsIcon

34697

无需使用任何工具,此程序将查找您程序中的内存泄漏。

引言

市场上有很多用于检测内存泄漏的工具。在这里,我编写了一个程序,需要将其包含在您的源代码文件中,它将提供所需的信息来查找内存泄漏发生的位置。

有两个文件,一个是 findLeak.c,另一个是 findLeak.h。源代码文件是 test.c,这是您想要检查内存泄漏的程序。

其原理是,当用户调用库函数“malloc 或 calloc”来分配动态内存时,我们必须调用我们自己的 malloc 或 calloc(在我的源代码中,用 'MyCalloc' 函数代替 'calloc',用 'MyMalloc' 函数代替 'malloc')。因此,您需要将 malloc 定义为您的 malloc,并在 .c 文件中取消定义 malloc 和 calloc。 这样我们就可以调用我们的 MyMalloc 或 MyCalloc 函数,并在该函数中调用另一个函数,该函数保存有关已分配多少内存的所有信息。 我们对库函数“free”进行相同的操作,以释放内存(在我的源代码中,使用“MyFree”代替 free 函数)。

使用代码


现在,为了保存信息,我创建了一个简单的单链表。它将在用户调用“malloc”或“calloc”函数时添加内存信息,并在用户调用“free”函数时也保存信息。

通过程序您可以很容易地理解。

头文件:findLeak.h

#define   uint          unsigned int 
#define   cchar         const char  
#define  OutFile       "/home/asadulla/test/MemLeakInfo.txt"   // Just Suppose

#define  MAX_FILENAME_LENGTH    256
#define  calloc(objs, nSize)    MyCalloc (objs, nSize, __FILE__, __LINE__)
#define  malloc(nSize)          MyMalloc (nSize, __FILE__, __LINE__)
#define  free(rMem)             MyFree(rMem)

// This structure is keeping info about memory leak

struct InfoMem
{
    void *addr;
    uint nSize;
    char fileName[MAX_FILENAME_LENGTH];
    uint lineNumber;
};

typedef struct InfoMem infoMem;

//This is link list of InfoMem which keeps a List of memory Leak in a source file

struct LeakMem
{
    infoMem memData;
    struct LeakMem *nxt;
};

typedef struct LeakMem leakMem;

void WriteMemLeak(void);

void SubAddMemInfo(void *rMem, uint nSize,  cchar  *file, uint lno);

void SubAdd(infoMem alloc_info);

void ResetInfo(uint pos); //erase

void DeleteAll(void); //clear(void);

void *MyMalloc(uint size, cchar *file, uint line);

void *MyCalloc(uint elements, uint size, cchar * file, uint lno);

void  MyFree(void * mem_ref);



源文件:findLeak.c

#include    <stdio.h>
#include    <malloc.h>
#include    <string.h>
#include    "findLeak.h"

#undef        malloc
#undef        calloc
#undef         free

static leakMem * ptr_start = NULL;
static leakMem * ptr_next =  NULL;

// -----------------------------------------------------------

// Name: MyMalloc

// Desc: This is hidden to user. when user call malloc function then 
//       this function will be called.

void *MyMalloc (uint nSize, cchar* file, uint lineNumber)
{
    void * ptr = malloc (nSize);
    if (ptr != NULL) 
    {
        SubAddMemInfo(ptr, nSize, file, lineNumber);
    }
    return ptr;
}


// -----------------------------------------------------------

// Name: MyCalloc

// Desc: This is hidden to user. when user call calloc function then 
//       this function will be called.

void * MyCalloc (uint elements, uint nSize, const char * file, uint lineNumber)
{
    uint tSize;
    void * ptr = calloc(elements , nSize);
    if(ptr != NULL)
    {
        tSize = elements * nSize;
        SubAddMemInfo (ptr, tSize, file, lineNumber);
    }
    return ptr;
}



// -----------------------------------------------------------

// Name: SubAdd

// Desc: It's actually  Adding the Info.


void SubAdd(infoMem alloc_info)
{
    leakMem * mem_leak_info = NULL;
    mem_leak_info = (leakMem *) malloc (sizeof(leakMem));
    mem_leak_info->memData.addr = alloc_info.addr;
    mem_leak_info->memData.nSize = alloc_info.nSize;
    strcpy(mem_leak_info->memData.fileName, alloc_info.fileName); 
    mem_leak_info->memData.lineNumber = alloc_info.lineNumber;
    mem_leak_info->nxt = NULL;
    if (ptr_start == NULL)
    {
        ptr_start = mem_leak_info;
        ptr_next = ptr_start;
    }
    else {
        ptr_next->nxt = mem_leak_info;
        ptr_next = ptr_next->nxt;    
    }
}


// -----------------------------------------------------------

// Name: ResetInfo

// Desc: It erasing the memory using by List on the basis of info( pos)

void ResetInfo(uint pos)
{
    uint index = 0;
    leakMem * alloc_info, * temp;

    if(pos == 0)
    {
        leakMem * temp = ptr_start;
        ptr_start = ptr_start->nxt;
        free(temp);
    }
    else 
    {
        for(index = 0, alloc_info = ptr_start; index < pos; 
        alloc_info = alloc_info->nxt, ++index)
        {
            if(pos == index + 1)
            {
                temp = alloc_info->nxt;
                alloc_info->nxt =  temp->nxt;
                free(temp);
                break;
            }
        }
    }
}



// -----------------------------------------------------------

// Name: DeleteAll

// Desc: It deletes the all elements which resides on List


void DeleteAll()
{
    leakMem * temp = ptr_start;
    leakMem * alloc_info = ptr_start;
    while(alloc_info != NULL) 
    {
        alloc_info = alloc_info->nxt;
        free(temp);
        temp = alloc_info;
    }
}



// -----------------------------------------------------------

// Name: MyFree

// Desc:


void MyFree(void * mem_ref)
{
    uint loop;
   // if the allocated memory info is part of the list, removes it
    leakMem  *leak_info = ptr_start;
    /* check if allocate memory is in our list */
    for(loop = 0; leak_info != NULL; ++loop, leak_info = leak_info->nxt)
    {
        if ( leak_info->memData.addr == mem_ref )
        {
            ResetInfo(loop);
            break;
        }
    }
    free(mem_ref);
}


// -----------------------------------------------------------
// Name: SubAddMemInfo

// Desc: it also fill the the Info


void SubAddMemInfo (void * mem_ref, uint nSize, cchar * file, uint lineNumber)
{
    infoMem AllocInfo;

    /* fill up the structure with all info */

    memset( &AllocInfo, 0, sizeof ( AllocInfo ) );
    AllocInfo.addr     = mem_ref;
    AllocInfo.nSize = nSize;
    strncpy(AllocInfo.fileName, file, MAX_FILENAME_LENGTH);
    AllocInfo.lineNumber = lineNumber;

    /* SubAdd the above info to a list */
    SubAdd(AllocInfo);
}


// -----------------------------------------------------------

// Name: WriteMemLeak

// Desc: It writes information about Memory leaks in a file 
//       Example: File is as : "/home/asadulla/test/MemLeakInfo.txt"


void WriteMemLeak(void)
{
    uint index;
    leakMem *leak_info;
    FILE * fp_write = fopen(OutFile, "wt");
    char info[1024];
    if(fp_write != NULL)
    {
        sprintf(info, "%s\n", "SUMMARY ABOUT MEMORY LEAKS OF YOUR SOURCE FILE ");
        fwrite(info, (strlen(info) + 1) , 1, fp_write);
        sprintf(info, "%s\n", "-----------------------------------");   
        fwrite(info, (strlen(info) + 1) , 1, fp_write);

        for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->nxt)
        {
            sprintf(info, "Name of your Source File : %s\n", leak_info->memData.fileName);
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, "Starting Address : %d\n", leak_info->memData.addr);
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, " Total size Of memory Leak : %d bytes\n", leak_info->memData.nSize);            
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, "Line Number for which no DeAllocation    : %d\n", leak_info->memData.lineNumber);
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            sprintf(info, "%s\n", "-----------------------------------");   
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
            fwrite(info, (strlen(info) + 1) , 1, fp_write);
        }
    }  
    DeleteAll();
}



用户必须将这两个文件(头文件和源文件)包含在他的源代码中,以查找内存泄漏。

用于检测内存泄漏的源文件如下。您可以在这里提供您自己的源代码,并且在该源代码中,您只需要写一行来包含文件:#include"findLeak.h"


测试:test.c

代码:c
#include<malloc.h>
#include"findLeak.h"

int main()
{
     int *p1 = (int *)malloc(10);
     int *p2 = (int *)calloc(10, sizeof(int));
     char *p3 = (char *) calloc(15, sizeof(float));
     float *p4 = (float*) malloc(16);
     free(p2);
     WriteMemLeak();
     return 0;
 }

现在用户可以在控制台中编译这些程序,如下所示:
> g++ test.c findLeak.c
并给出运行命令
> ./a.out

然后转到您定义了宏“OutFile”的目录,并打开该定义的 文件,您将看到结果。

以上源代码的输出如下:

代码:output
SUMMARY ABOUT MEMORY LEAKS OF YOUR SOURCE FILE 
     -----------------------------------

Name of your Source File                 : test.c
Starting Address                         : 184960
Total size Of memory Leak                : 10 bytes
Line Number for which no DeAllocation    : 7
-----------------------------------
-----------------------------------

Name of your Source File                 : test.c
Starting Address                         : 187104
 Total size Of memory Leak               : 60 bytes
Line Number for which no DeAllocation    : 9

-----------------------------------
-----------------------------------
Name of your Source File                 : test.c
Starting Address                         : 184984
 Total size Of memory Leak               : 16 bytes
Line Number for which no DeAllocation    : 10
-----------------------------------
----------------------------------- 



现在您可以尝试创建您自己的测试用例,就像 test.c 一样。
© . All rights reserved.