如何在程序中找到何处在不断占用内存

一个简单而有效的方案:

分配的时候多分配一点空间作头,记下分配的文件名和行号,把所有的头连成一个环形双
链表,释放的时候从双链表中删除,并释放头。

结束的时候只要检查这个双链表是否唯恐就知道哪里泄漏内存了

在Windows DDK里的简化代码:

in xxx.h

// the real heap function
void* sys_malloc(size_t size);
void sys_free(void* p);

//
// Heap tracking mechanism
#if DBG
void StartHeapTracking(void);
void StopHeapTracking(void);

void* sys_malloc_track(size_t size, const char* File, unsigned int Line);
void sys_free_track(void* mem);

// these macros will cover real heap functions in debug version
#define sys_malloc(size) sys_malloc_track(size, __FILE__, __LINE__)
#define sys_free    sys_free_track
#else
#define StartHeapTracking()
#define StopHeapTracking()
#endif

in xxx_dbg.c
//
// Heap tracking
//

#if DBG
struct HEAP_TRACKING_RECORD
{
    LIST_ENTRY Link;
    size_t Size;
    const char* File;
    unsigned int Line;
};

// the doubly linked list header
static LIST_ENTRY HeapTrack;
static KSPIN_LOCK HeapTrackLock;

void StartHeapTracking(void)
{
    InitializeListHead(&HeapTrack);
    KeInitializeSpinLock(&HeapTrackLock);
}

void StopHeapTracking(void)
{
    // check memory leak
    if(!IsListEmpty(&HeapTrack))
    {
        LIST_ENTRY* p;
        ASSERT(FALSE); // break here if memory leak
        for(p=HeapTrack.Flink; p!=&HeapTrack; p=p->Flink)
        {
            struct HEAP_TRACKING_RECORD* q = 
                CONTAINING_RECORD(p, struct HEAP_TRACKING_RECORD, Link);
            DbgPrint(
                "Memory leak: %u bytes allocated in %s:%u./n", 
                (unsigned)q->Size, 
                q->File,
                q->Line
            );
        }
    }
}

// following code using real heap function
#undef sys_malloc
#undef sys_free

void* sys_malloc_track(size_t size, const char* File, unsigned int Line)
{
    struct HEAP_TRACKING_RECORD* mem = 
        sys_malloc(sizeof(struct HEAP_TRACKING_RECORD)+size);
    if(mem)
    {
        mem->Size = size;
        mem->File = File;
        mem->Line = Line;
        ExInterlockedInsertTailList(&HeapTrack, &mem->Link, &HeapTrackLock);
        return mem+1;
    }
    return NULL;
}

void sys_free_track(void* mem)
{
    if(mem)
    {
        struct HEAP_TRACKING_RECORD* p = 
            (struct HEAP_TRACKING_RECORD*)
            ((char*)mem-sizeof(struct HEAP_TRACKING_RECORD));

        RemoveEntryList(&p->Link);
        sys_free(p);
    }
}

#endif

使用的时候包含xxx.h, 
程序开始的时候先调用StartHeapTracking初始化,然后直接用sys_malloc, sys_free
分配和释放即可,结束的时候调用StopHeapTracking,就会把泄漏的内存块分配的地方
大小打印出来。这样在调试版每次分配要多耗费20字节的内存。如果不定义DBG预处理
符号,则等于用原来的sys_malloc和sys_free,不增加开销。

代码中用了Windows DDK中的双链表函数,其他操作系统下比如Linux有类似的实现。
没有的话自己写也很简单。

代码是驱动程序中的一部分,其中的spinlock是为了保护共享资源。
如果你的程序是单线程的,则可以不用加锁。

如果你没有DDK, 那么可以参考这些双链表函数相关的代码:

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

VOID
FORCEINLINE
InitializeListHead(
    IN PLIST_ENTRY ListHead
    )
{
    ListHead->Flink = ListHead->Blink = ListHead;
}

//
//  BOOLEAN
//  IsListEmpty(
//      PLIST_ENTRY ListHead
//      );
//

#define IsListEmpty(ListHead) /
    ((ListHead)->Flink == (ListHead))



VOID
FORCEINLINE
RemoveEntryList(
    IN PLIST_ENTRY Entry
    )
{
    PLIST_ENTRY Blink;
    PLIST_ENTRY Flink;

    Flink = Entry->Flink;
    Blink = Entry->Blink;
    Blink->Flink = Flink;
    Flink->Blink = Blink;
}

PLIST_ENTRY
FORCEINLINE
RemoveHeadList(
    IN PLIST_ENTRY ListHead
    )
{
    PLIST_ENTRY Flink;
    PLIST_ENTRY Entry;

    Entry = ListHead->Flink;
    Flink = Entry->Flink;
    ListHead->Flink = Flink;
    Flink->Blink = ListHead;
    return Entry;
}



PLIST_ENTRY
FORCEINLINE
RemoveTailList(
    IN PLIST_ENTRY ListHead
    )
{
    PLIST_ENTRY Blink;
    PLIST_ENTRY Entry;

    Entry = ListHead->Blink;
    Blink = Entry->Blink;
    ListHead->Blink = Blink;
    Blink->Flink = ListHead;
    return Entry;
}


VOID
FORCEINLINE
InsertTailList(
    IN PLIST_ENTRY ListHead,
    IN PLIST_ENTRY Entry
    )
{
    PLIST_ENTRY Blink;

    Blink = ListHead->Blink;
    Entry->Flink = ListHead;
    Entry->Blink = Blink;
    Blink->Flink = Entry;
    ListHead->Blink = Entry;
}


VOID
FORCEINLINE
InsertHeadList(
    IN PLIST_ENTRY ListHead,
    IN PLIST_ENTRY Entry
    )
{
    PLIST_ENTRY Flink;

    Flink = ListHead->Flink;
    Entry->Flink = Flink;
    Entry->Blink = ListHead;
    Flink->Blink = Entry;
    ListHead->Flink = Entry;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值