3

I'm working in Unix/Linux with C. I have a basic understanding of how memory allocation works, enough to know that if I malloc() then free(), I'm not likely going to actually free an entire page; thus if I use getrusage() before and after a free() I'm not likely going to see any difference.

I'd like to write a unit test for a function which destroys a data structure to see that the memory regions involved has actually been freed. I'm open to an OS-dependent solution, in which case my primary platform is

Linux beast 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

with OS X and FreeBSD as secondaries. I'm also open to a drop in replacement malloc() if there's a solution that makes checking free() relatively easy.

To be clear, I'm testing a routine that is to delete a large data structure, and I want to make sure that all the allocated regions are actually freed, in essence a unit test that the particular unit does not have a basic memory leak. I'm going to assume that free() does its job, I'm just making sure that my code actually calls free on all allocated regions it's responsible for.

In this particular case it's a tree structure and for each piece of data in the tree the structure is responsible for calling the routine that deletes the data stored in the tree as well, which might be some other arbitrary thing...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Michael Conlen
  • 1,959
  • 2
  • 17
  • 19
  • I really don't think this is necessary.. you free it and forget it. –  Jul 10 '12 at 23:53
  • To clarify; you want a test that confirms that the freed physical memory has been returned to the OS? – Oliver Charlesworth Jul 10 '12 at 23:55
  • 1
    I assumed that the question was how to detect that `free` had not been called. If the question is "does my `free` work?" then there's no question here. Yes, your `free` does work. The compiler vendor is in charge of testing that. Pointless for you to try to do it. – David Heffernan Jul 10 '12 at 23:59
  • You can always `mmap()`/`munmap()` and dole out slices yourself. However, generally it's not a big deal that you don't return it to the OS. If the page isn't being used and there is a demand for memory, it'll be swapped out of RAM. – FatalError Jul 11 '12 at 00:00

4 Answers4

2

I hate to do this again, but after a night of sleep I found an explicit answer, it comes from SVID (does anyone even remember System V?), but is incorporated in glibc on Linux, likely through it's use in dlmalloc; hence it can be used on other system by using dlmalloc() as a drop in replacement malloc.

use the routine

struct mallinfo mallinfo(void);

and struct mallinfo is

struct mallinfo
{
  int arena;    /* non-mmapped space allocated from system */
  int ordblks;  /* number of free chunks */
  int smblks;   /* number of fastbin blocks */
  int hblks;    /* number of mmapped regions */
  int hblkhd;   /* space in mmapped regions */
  int usmblks;  /* maximum total allocated space */
  int fsmblks;  /* space available in freed fastbin blocks */
  int uordblks; /* total allocated space */
  int fordblks; /* total free space */
  int keepcost; /* top-most, releasable (via malloc_trim) space */
};

In particular arena and uordblks will give you the number of bytes allocated by malloc() independent of the size of the pages requested from the OS using sbrk() or mmap(), which are given by arena and hblkhd.

Michael Conlen
  • 1,959
  • 2
  • 17
  • 19
2

My best suggestion is to use valgrind.

They make wrappers for malloc and free and shows you memory leaks better than you will do with a homegrown system. And they catch all kinds of other errors not easily spotted and tested with unittests like uninitialized variables.

So always run your tests with valgrind and make your success criteria that all tests pass and that valgrind shows no errors and no un-allocated memory.

PS: It might be a bit of a pain getting started if you already have a bit of a codebase, but if you take the time to fix all the valgrind errors both your tests and your system will be much more reliable!

barsju
  • 4,408
  • 1
  • 19
  • 24
1

One trick you can use for all kinds of memory leak debug is to simply increase the scale until the problem stands out more. Do one malloc/free cycle, then capture the results of getrusage(), then do 1000 more malloc/free cycles and ensure your process didn't actually allocate more memory. By leaking 1000 of them you increase the scale of the problem to the point where it stands out.

If you want something more deterministic (but slightly more intrusive) you can override malloc() and free() to track allocations and observe the tracking data from the test harness. You can find several examples of debug malloc libraries to show you how it's done.

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150
  • As far as I can see from http://linux.die.net/man/2/getrusage, Linux is not filling in the memory usage. – thoni56 Aug 26 '13 at 04:45
-1

The easiest way is to make wrappers for malloc and free. If you use the real malloc and free then the following could happen:

  1. you allocate memory
  2. you do something with that memory
  3. you free the memory
  4. someone else in the OS, even something else in your own code, needs memory and the OS allocates that memory elsewhere, since it's now free
  5. you test to see if the memory is free, and it's not, but you think it should be, so you get a false test failure.
Yusuf X
  • 14,513
  • 5
  • 35
  • 47
  • This really only happens in realtime execs, where you really need to be careful. In most other OS:es you have virtual memory management. – thoni56 Aug 26 '13 at 05:53