【问题标题】:Memory not freed after calling free()调用 free() 后内存未释放
【发布时间】:2011-07-18 23:16:27
【问题描述】:

我有一个简短的程序,它通过向其中添加节点来生成链表,然后释放链表分配的内存。

Valgrind 不报告任何内存泄漏错误,但进程继续持有分配的内存。

只有在将分配的内存从 sizeof(structure_name) 更改为固定数字 512 后,我才能修复错误。(请参阅注释代码)

这是一个错误还是正常操作? 这是代码:

#include <execinfo.h>
#include <stdlib.h>
#include <stdio.h>


typedef struct llist_node {
  int ibody;
  struct llist_node * next;
  struct llist_node * previous;
  struct llist * list;
}llist_node;

typedef struct  llist {
  struct llist_node * head;
  struct llist_node * tail;
  int id;
  int count;
}llist;

llist_node * new_lnode (void) {
  llist_node * nnode = (llist_node *) malloc ( 512 );
  //  llist_node * nnode = (llist_node *) malloc ( sizeof(llist_node) );
  nnode->next = NULL;
  nnode->previous = NULL;
  nnode->list = NULL;
  return nnode;
}

llist * new_llist (void) {
  llist * nlist = (llist *) malloc ( 512 );
  //  llist * nlist = (llist *) malloc ( sizeof(llist) );
  nlist->head = NULL;
  nlist->tail = NULL;
  nlist->count = 0;
  return nlist;
}

void add_int_tail ( int ibody, llist * list ) {
  llist_node * nnode = new_lnode();
  nnode->ibody = ibody;
  list->count++;
  nnode->next = NULL;
  if ( list->head == NULL ) {
    list->head = nnode;
    list->tail = nnode;
  }
  else {
    nnode->previous = list->tail;
    list->tail->next = nnode;
    list->tail = nnode;
  }
}

void destroy_list_nodes ( llist_node * nodes ) {
  llist_node * llnp = NULL;
  llist_node * llnpnext = NULL;
  llist_node * llnp2 = NULL;
  if ( nodes == NULL )
    return;
  for ( llnp = nodes; llnp != NULL; llnp = llnpnext ) {
    llnpnext = llnp->next;
    free (llnp);
  }
  return;
}

void destroy_list ( llist * list ) {
  destroy_list_nodes ( list->head );
  free (list);
}

int main () {
  int i = 0;
  int j = 0;
  llist * list = new_llist ();

  for ( i = 0; i < 100; i++ ) {
    for ( j = 0; j < 100; j++ ) {
      add_int_tail ( i+j, list );
    }
  }
  printf("enter to continue and free memory...");
  getchar();
  destroy_list ( list );
  printf("memory freed. enter to exit...");
  getchar();
  printf( "\n");
  return 0;
}

【问题讨论】:

    标签: memory malloc free memory-leaks


    【解决方案1】:

    如果“进程继续持有分配的内存”是指ps 没有报告进程的内存使用量减少,那是完全正常的。出于各种原因,将内存返回到进程的堆并不一定会使进程将其返回到操作系统。如果您在一个大循环中一遍又一遍地创建和销毁您的列表,并且您的进程的内存使用量不会无限增长,那么您可能没有真正的内存泄漏。

    [编辑添加:另见Will malloc implementations return free-ed memory back to the system?]

    [再次编辑添加:顺便说一句,分配 512 字节块使问题消失的最可能原因是您的 malloc 实现以某种方式特别对待较大的块,使其更容易注意到是不再使用的整个页面——如果要将任何内存返回给操作系统,这是必要的。]

    【讨论】:

    • 是的,我的意思是ps。释放列表占用的内存后,操作系统仍然内存不足。当需要更多内存时,例如分配另一个链表,系统开始回收。
    • 你的意思是分配另一个链表在同一个程序中?因为在你从第一个列表中释放了所有节点之后,内存应该可以用于以后的分配。 (有时可能会发生可用内存碎片化的情况,以便有足够的可用空间但不是您需要的大小,但这似乎不应该成为问题。)如果没有发生这种情况,那么也许你真的有内存泄漏。我看一下代码。
    • 我没有在代码中看到任何明显疯狂的东西。 (这当然不能保证没有错误。但在我看来,它应该释放一切。)
    • 如果像 free 这样的 shell 命令不能提供可靠的可用内存量,那么我们如何知道可用内存量?
    【解决方案2】:

    我在这里找到了我的问题的答案:

    http://linuxupc.upc.es/~pep/OLD/man/malloc.html

    如果满足__noshrink配置的条件,可以将堆扩展后的内存返回给内核。只有这样 ps 才会注意到内存已被释放。

    有时配置它很重要,特别是当内存使用量很小但堆大小大于可用的主内存时。因此,即使所需的内存小于可用的主内存,程序也会丢弃。

    【讨论】:

    • 完全 OT,但是:我喜欢那个 URL。 “Old man malloc, dat old man malloc ...” 可惜没有真正称为“river”的 Linux 命令或系统调用。
    猜你喜欢
    • 1970-01-01
    • 2012-05-15
    • 2011-05-31
    • 1970-01-01
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多