我正在用 c 开发一个项目,我试图了解如何调试一个使我的程序崩溃的晦涩错误。它有点大,通过制作较小版本的代码来隔离问题的尝试不起作用。所以我试图想出一种方法来调试和查明内存泄漏。
我想出了以下计划:我知道问题来自于运行某个函数,并且该函数递归调用自身。所以我想我可以对我的程序内存分配进行快照。因为我不知道杰克在幕后发生了什么(我知道一点不足以在这种情况下有用):
typedef struct record_mem {
int num_allocs;
int num_frees;
int size_space;
int num_structure_1;
...
int num_structure_N;
int num_records;
struct record_mem *next;
} RECORD;
extern RECORD *top;
void pushmem(RECORD **top)
{
RECORD *nnew = 0;
RECORD *nnew = (RECORD *)malloc(sizeof(RECORD));
nnew->num_allocs=1;
nnew->num_frees=0;
nnew->size_space=sizeof(RECORD);
nnew->num_structure_1=0;
...
nnew->num_structure_N=0;
nnew->num_records=1;
nnew->next=0;
if(*top)
{
nnew->num_allocs+=(*top)->num_allocs;
nnew->num_frees=(*top)->num_frees;
nnew->size_space+=(*top)->size_space;
nnew->num_structure_1=(*top)->num_allocs;
...
nnew->num_structure_N=(*top)->num_allocs;
nnew->num_records+=(*top)->num_records;
nnew->next=*top;
}
*top=nnew;
}
我的想法是在我的程序崩溃之前打印出我保存的内存记录的内容(由于 GDB,我知道它在哪里崩溃)。
然后在整个程序中(对于我的程序中的每个数据结构,我都有一个类似的推送功能,如上)我可以简单地添加一个带有统计数据结构分配加上总堆栈(堆?)内存分配的函数(我可以跟踪的)。只要我觉得需要记录我的程序运行的快照,我就会简单地制作更多的 memory_record 结构。问题是,如果我无法以某种方式记录实际使用了多少内存,则此内存资产负债表记录将无济于事。
但是我该怎么做呢?另外,我将如何考虑悬空指针和泄漏?我正在使用 OS X,目前正在查找如何记录堆栈指针和其他内容。
编辑:既然你问:valgrind的输出:(closure()是从main调用的函数,它返回错误的指针:它应该返回双向链表的头部,traversehashmap()是从closure()调用的函数我用来计算额外的节点并将其附加到链表中,并且它递归地调用自身,因为它需要在节点之间跳转。)
jason-danckss-macbook:project Jason$ valgrind --leak-check=full --tool=memcheck ./testc
Will attempt to compute closure of AB:
Result: testcl: 0x10000d0b0
==7682== Invalid read of size 8
==7682== at 0x100001D4E: printrelation2 (relation.h:490)
==7682== by 0x100003CFE: main (test-computation.c:47)
==7682== Address 0x10000cee8 is 8 bytes inside a block of size 24 free'd
==7682== at 0xD828: free (vg_replace_malloc.c:450)
==7682== by 0x100001232: destroyrelation2 (relation.h:161)
==7682== by 0x100003407: destroyallhashmap (computation.h:333)
==7682== by 0x1000039E1: closure (computation.h:539)
==7682== by 0x100003CBE: main (test-computation.c:38)
==7682==
==7682==
==7682== HEAP SUMMARY:
==7682== in use at exit: 5,360 bytes in 48 blocks
==7682== total heap usage: 99 allocs, 51 frees, 6,640 bytes allocated
==7682==
==7682== 48 (24 direct, 24 indirect) bytes in 1 blocks are definitely lost in loss record 33 of 37
==7682== at 0xC283: malloc (vg_replace_malloc.c:274)
==7682== by 0x100001104: getnewrelation (relation.h:134)
==7682== by 0x100001848: copyrelation (relation.h:343)
==7682== by 0x100003991: closure (computation.h:531)
==7682== by 0x100003CBE: main (test-computation.c:38)
==7682==
==7682== 1,128 (24 direct, 1,104 indirect) bytes in 1 blocks are definitely lost in loss record 36 of 37
==7682== at 0xC283: malloc (vg_replace_malloc.c:274)
==7682== by 0x100002315: getnewholder (dependency.h:129)
==7682== by 0x100003B17: main (test-computation.c:14)
==7682==
==7682== LEAK SUMMARY:
==7682== definitely lost: 48 bytes in 2 blocks
==7682== indirectly lost: 1,128 bytes in 44 blocks
==7682== possibly lost: 0 bytes in 0 blocks
==7682== still reachable: 4,096 bytes in 1 blocks
==7682== suppressed: 88 bytes in 1 blocks
==7682== Reachable blocks (those to which a pointer was found) are not shown.
==7682== To see them, rerun with: --leak-check=full --show-reachable=yes
==7682==
==7682== For counts of detected and suppressed errors, rerun with: -v
==7682== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)