Locating Memory Leaks with MallocDebug
I am currently working on a interesting project written in C (more about the project in a few days or weeks) which requires a very clean memory management. I decided to write it in C because it does pretty long and complex calculations and I wanted to do it fast. But using C also means to do the whole memory management by myself. This can be a very hard job especially if a program is very memory-intensive.
One of the biggest issue in memory management is to track down memory leaks.
"A memory leak is a particular kind of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed." ([Wikipedia](http://en.wikipedia.org/wiki/Memory_leak)).
If a computer program does not use a lot of memory a memory leak might not even be recognized by the programmer or the user. It looks differently if a program does a lot of malloc()'s and free()'s. Unreleased memory will be wasted and your program will get slower until your main memory is full.
Here is a typical example of how a memory leak is opened:
#include
#include
void initA(int **aPtr) {
*aPtr = (int*)malloc(sizeof(int));
}
void initB(int **bPtr) {
*bPtr = (int*)malloc(sizeof(int));
}
int main(int argc, const char * argv[]) {
int *aPtr;
int *bPtr;
initA(&aPtr);
initB(&bPtr);
aPtr = bPtr;
// don't exit immediately
getchar();
return 0;
}
In this example we create two integer pointers (**aPtr** and **bPtr**) and two initialization functions (**initA()** and **initB()**) which will allocate memory for our two pointers.
After the initialization we assign **bPtr** to **aPtr**.
At this point we have a memory leak. Why? Because we deleted our only reference to the memory location stored in **aPtr** we can never reach that memory location again. It's lost - forever (well, until our program exits).
In this example the memory leak is more or less obvious. But think of a multi hundred line C code program with structs and other funny C stuff. Locating memory leaks is nearly impossible - without any tools.
Fortunately, [Apple](http://www.apple.com) ships a tool called **MallocDebug** with it's Xcode IDE. With **MallocDebug** the developer get's the chance to see where the unreachable memory (if any) was originally allocated. Following the corresponding pointer might lead to the location in the code where the leak occurs.
Let's use the above example to take a look at **MallocDebug**.
Create a new Xcode project using the Standard Tool template. Paste the above code in your main.c file and try to compile and run it. You shouldn't see any warnings or errors.
The **getchar()** call just prevents our little program from immediate termination because **MallocDebug** can only analyze the memory while the program is running.
To start **MallocDebug**, simply select **Launch Using Performance Tool** -> **MallocDebug** from Xcode's **Debug** menu.

**MallocDebug** will be started, but not our program. Select the **MallocDebug** window and click on the **Launch** button. Now our program will be started.
In the current view you can see that our programm takes about 650K of memory. Feel free to browse through the tree to see where this memory is used.

To find leaks, select **Leaks** from the second drop-down menu.

After a short time you can see, that 4 bytes originally allocated in initA() are lost.

Add the following line before the line where we assign **bPtr** to **aPtr**:
free(aPtr);
Compile the program and run **MallocDebug** again. As expected we won't have a leak anymore. The freed memory was returned to the operating system and can be assigned to the next process requesting memory. Great!
February 7th, 2008 - 17:55
Have you tried this in Leopard? I used your example but MallocDebug doesn’t see the leak. Strange…
February 10th, 2008 - 22:11
You’re right. The example isn’t working on Leopard anymore. I’ll update it as soon as I found the reason. Thanks!
February 21st, 2008 - 23:15
Yes, the leaks(1) utility is definitely no longer working properly on Leopard. I filed a bug with Apple but I haven’t heard anything back about it.
This is another example:
include
include
include
static void foo(void)
{
malloc(256);
}
static void leaks(void)
{
char cmd[64];
sprintf(cmd, “/usr/bin/leaks %u”, getpid());
system(cmd);
}
int main(void)
{
atexit(leaks);
foo();
foo();
foo();
return 0;
}
March 24th, 2008 - 17:40
I’m currently trying to use MallocDebug
I run it (Debug>Launch using performance tool>MallocDebug),
I make sure it’s pointing the the right file,
Then I click launch.
It hangs for about a minutes then says “Read Data, Unable to read malloc from …”
I’m using OS X 10.4.11 (Tiger?)
Xcode Ver 2.4.1
Component versions
Xcode IDE: 762.0
Xcode Core: 762.0
ToolSupport: 764.0
Am I doing something wrong ?
Please Help!
August 29th, 2008 - 19:58
Hi,
I am also facing the same problem with MallocDebug tools. Please let me know if you know the ans.
yathi
March 14th, 2009 - 06:13
using leopard and it works fine.
this is a bit late here, but it seems you just need to be in debug mode rather than release mode. or, in other words, make sure you aren’t heavily performing gcc optimization…
or, maybe they fixed the bug?