2

I have a short program that generates a linked list by adding nodes to it, then frees the memory allocated by the linked list.

Valgrind does not report any memory leak errors, but the process continues to hold the allocated memory.

I was only able to fix the error after I changed the memory allocated from sizeof(structure_name) to fixed number 512. (see commented code)

Is this a bug or normal operation? Here is the code:

#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;
}
Shant
  • 41
  • 1
  • 4

2 Answers2

6

If by "the process continues to hold the allocated memory" you mean that ps doesn't report a decrease in the process's memory usage, that's perfectly normal. Returning memory to your process's heap doesn't necessarily make the process return it to the operating system, for all sorts of reasons. If you create and destroy your list over and over again, in a big loop, and the memory usage of your process doesn't grow without limit, then you probably haven't got a real memory leak.

[EDITED to add: See also Will malloc implementations return free-ed memory back to the system? ]

[EDITED again to add: Incidentally, the most likely reason why allocating 512-byte blocks makes the problem go away is that your malloc implementation treats larger blocks specially in some way that makes it easier for it to notice when there are whole pages that are no longer being used -- which is necessary if it's going to return any memory to the OS.]

Community
  • 1
  • 1
Gareth McCaughan
  • 19,888
  • 1
  • 41
  • 62
  • Yes, I mean ps. After freeing the memory taken by the list, the OS still is out of memory. When more memory is requires, e.g. allocating another linked-list, the system starts trashing. – Shant Mar 20 '11 at 00:58
  • Do you mean allocating another linked list *in the same program*? Because after you've freed all the nodes from the first list, the memory ought to be available for later allocations. (It can sometimes happen that the available memory gets fragmented so that there's plenty of free space but not in the sizes you need, but that doesn't seem like it should be an issue here.) If that isn't happening, then perhaps you really do have a memory leak. I'll take a look at the code. – Gareth McCaughan Mar 20 '11 at 01:14
  • I don't see anything obviously crazy in the code. (Which of course doesn't guarantee there are no bugs. But it looks to me as if it should be freeing everything.) – Gareth McCaughan Mar 20 '11 at 01:19
  • if shell command like free does not give reliable amount of free memory, than how can we know amount of free memory ? – ransh Jul 12 '17 at 07:13
2

I discovered the answer to my question here:

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

The memory after expanding the heap can be returned back to kernel if the conditions configured by __noshrink are satisfied. Only then the ps will notice that the memory is freed.

It is important to configure it sometimes particularly when the memory usage is small, but the heap size is bigger than the main memory available. Thus the program trashes even if the required memory is less than the available main memory.

Shant
  • 41
  • 1
  • 4
  • Totally OT, but: I love that URL. "Old man malloc, dat old man malloc ..." Too bad there isn't a Linux command or syscall actually called "river". – Gareth McCaughan Mar 20 '11 at 19:35