【问题标题】:Why would this memory leak occur为什么会发生这种内存泄漏
【发布时间】:2021-08-15 14:35:47
【问题描述】:

我在 valgrind 中遇到此错误

==399==ERROR: LeakSanitizer: detected memory leaks
 Direct leak of 240 byte(s) in 15 object(s) allocated from:
     #0 0x7f2a8cfadb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
     #1 0x401371 in push /src/main.c:88
     #2 0x401725 in buildTree /src/main.c:126
     #3 0x4027e1 in encode /src/main.c:31
     #4 0x402c8b in main /src/main.c:432
     #5 0x7f2a8c761b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)

我的推送功能:

void push(Heap* heap, Node* node) {
    if (heap->heapSize + 1 >= heap->capacity) {
        int capacity_ = heap->capacity * 2;
        qNode** arr_ = realloc(heap->arr,sizeof(qNode) *  capacity_);
        heap->arr = arr_;
        heap->capacity = capacity_;
    }
    heap->arr[heap->heapSize] = (qNode*) malloc(sizeof(qNode)); //line 88, where the leak occurs
    heap->arr[heap->heapSize]->data = node;
    heap->arr[heap->heapSize]->priority = node->count;
    heap->heapSize = heap->heapSize + 1;
    for (int i = (heap->heapSize/2)-1; i > -1; i--) {
        heapify(heap, i);
    }
}

我不明白为什么会发生泄漏,因为在程序结束时我清除了整个堆->arr

void freeHeap(Heap* heap) {
    for (int i = 0; i < heap->heapSize; i++) {
        freeTree(heap->arr[i]->data);
        free(heap->arr[i]);
    }
    free(heap->arr);
    free(heap);
}

Entire code

【问题讨论】:

  • 尝试注释掉heapify 并重新运行您的程序,只是猜测您在heapify 中有错误。
  • 对于未来的项目,请尝试在每个部分之间进行测试(如运行 Valgrind)以分段方式进行。您添加的每个和平都应该非常小并且易于单独测试。请记住在构建时启用额外警告并将它们视为必须修复的错误。
  • 对于您当前的项目,如果您使用的是 VCS(版本控制系统,例如 Git),则回滚直到错误消失。然后一个一个地重新应用每个提交,直到它出现,你就知道是哪段代码导致了它。如果您没有使用 VCS,请逐句注释代码语句(同时确保您不会留下指针访问等),直到它消失。取消注释直到它返回并且最后一块可能是导致它的那个。
  • 我的两分钱:qNode** arr_ = realloc(heap-&gt;arr,sizeof(qNode) * capacity_); 应该是qNode** arr_ = realloc(heap-&gt;arr,sizeof(qNode *) * capacity_);,因为heap-&gt;arrqNode 指针数组,而不是 n qNode 结构的分配空间。更重要的是,您应该始终检查来自malloccallocrealloc 的返回指针,它们可能会失败。如果不这样做,可能会导致泄漏(失败的realloc不会释放原始指针)。

标签: c memory-leaks valgrind


【解决方案1】:

当您在完整程序中看到运行 pop() 时,指向先前由 heap->arr[0] 指向的 qNode 的唯一指针将在 pop() 的返回值中传回。

qNode* pop(Heap* heap)
{
    qNode* result = heap->arr[0];
 
    heap->arr[0] = heap->arr[heap->heapSize - 1];
    heap->heapSize = heap->heapSize - 1;
 
    heapify(heap, 0);
    return result;
}

这意味着 pop() 的调用者现在持有指向该 qNode 的最后一个指针,并且有义务确保在指针超出范围之前释放 qNode。

您的代码包含几个 pop() 调用者未能执行此操作的地方。这是来自 buildTree 的示例(显示的最后一行)。 buildTree 返回时 qNode 被泄露,因为现在不再有任何指向该 qNode 的指针。

Node* buildTree(Heap* heap, int* tab) {
    for (int i = 0; i < 256; ++i) {
        if (tab[i]) {
            Node* node = createNode(tab[i], i, NULL, NULL);
            push(heap, node);.
    
    
        }
    }
     
    if (heap->heapSize == 1) {
        return pop(heap)->data;

【讨论】:

  • 我用qNode* qn = pop(heap); Node* n = pop(heap)-&gt;data; free(qn); return n; 替换了return pop(heap)-&gt;data;,但还是被泄露了
  • soz,这次是qNode** arr_ = realloc(heap-&gt;arr,sizeof(qNode*) * capacity_);heap-&gt;arr[0] = heap-&gt;arr[heap-&gt;heapSize - 1]; 中的堆缓冲区溢出。我知道没有更多的内存泄漏:)
  • 如果对你来说不难,请告诉我为什么会出现堆缓冲区溢出
  • 我认为您已经知道了这一点,但问题是在您的替换代码中,“Node *n = pop(heap)->data;”应该是“节点 *n = qn->data;”
  • 是的,这是一个错字,但在修复它之后,内存泄漏又回来了
猜你喜欢
  • 2016-01-01
  • 2013-12-01
  • 2018-06-08
  • 1970-01-01
  • 2011-08-07
  • 2011-05-13
  • 2011-06-28
  • 2011-01-17
  • 2011-12-19
相关资源
最近更新 更多