quote from http://ace.acadiau.ca/math/ACMMaC/howtos/mtrace.html
Finding Memory Leaks Using mtrace
When testing code on small samples, small problems such as memory leaks are often undetectable. However, once the program is run on a larger scale, existing memory leaks become larger problems; they often will cause a program to crash or to swap extensively (slowing performance drastically), and also affect any other programs running on the same system by reducing available memory.
To help avoid, or more often fix, such memory leaks, there are many tools available. One within the GNU platform is called mtrace.
Steps to Profiling a Program
1. Add a call to mtrace() at the very start of your main function, and include mcheck.h in the file containing the main program.
2. Compile the program with debug options set (i.e. the '-g' switch)
3. export a variable called MALLOC_TRACE which contains a filename where the trace data should be stored. Example: export MALLOC_TRACE=mtrace.out
4. Run the program, once
5. Run 'mtrace my_program mtrace.out' to view the output
1. Add the mtrace() call
mtrace works by adding hooks into calls which allocate and deallocate memory, logging these calls, and reporting on any mis-matches between the recorded allocations and deallocations. In order to begin recording information, these hooks have to be turned on. Calling the mtrace() function does this. In order to work properly, you must do this at THE VERY FIRST ACTION of the program. As well, since mtrace() is declared in mcheck.h, you'll have to include that as well.
For example, let's look at a simple program: #include <stdio.h> #include <stdlib.h> #include <mcheck.h> int main() { char *string; mtrace(); string = malloc(100 * sizeof(char)); return 0; }
Notice declarations are before the call to mtrace(), but any executed code comes after. The best place to call mtrace() is the very first executing line of code in main().
2. Compile program with debugging options
Although not strictly necessary, in order to get best use of mtrace, you should compile with debugging options set. This consists of adding '-g' to your compiling and linking commands.
So, if you were to compile a program composed of a single file, let's say hello.c, you would compile it with a command line resembling: gcc -g -o mtrace_test mtrace_test.c
However, if you were to compile a program consisting of multiple files, or where you have to do separate compilation and linking, you would have to supply -g on all compilation and linking commands. For example, given the files mtrace_test.c and file2.c, the commands would resemble the following: gcc -g -c mtrace_test.c gcc -g -c file2.c gcc -g -o mtrace_test mtrace_test.o file2.o
Often in larger software, you would modify the flags variables (CFLAGS, CXXFLAGS, FFLAGS, LD_OPTS and/or LDFLAGS) in your Makefile to add these, or you would set and export these as environment variables before running configure. An example of this last approach: export CFLAGS='-g' export LDFLAGS='-g' ./configure make
3. export MALLOC_TRACE
mtrace() saves its data to whatever file is named in the environment variable MALLOC_TRACE. So, in order to have the data saved, you must set this before running your program.
For bash, you could set the variable to 'mtrace.out' by running the following: export MALLOC_TRACE="mtrace.out"
For C shell, it would be: setenv MALLOC_TRACE mtrace.out
4. Run The Program, Once
Now you just need to run your program as usual. While it runs, it will save all the necessary data to the file specified in the MALLOC_TRACE environment variable.
I recommend running the program in such a way as to cover as much of the program's functionality as possible. If there are any problems, you want to try to make sure you trigger them.
5. View The Data
You should now have a file containing the trace data. In the case of the examples above, it would be mtrace.out. To view the data in a readable format, run the mtrace command, giving the program name and trace file name as arguments. Using the above examples, with our program name being mtrace_test and trace file name being mtrace.out, our command would be: mtrace mtrace_test mtrace.out
Assuming the C code at the beginning was the code in mtrace_test.c, the following output would be produced: Memory not freed: ----------------- Address Size Caller 0x0000000000501460 0x64 at /array/home/dcurrie/test/mtrace/mtrace_test.c:11
The address column is mostly meaningless. Feel free to ignore that - it can vary from run to run. More importantly, the entries in the "Memory not freed" report contains the file name and line number the allocation call has been traced to, and also contains the number of bytes allocated (0x64 is hexadecimal for 100)
So, the information tells us that data allocated on line 11 of mtrace_test.c is never deallocated, and so we should take corrective action to deallocate that particular memory.
Wrap-Up
Although in very small programs like what is used in the example, a quick visual inspection works well, when you expand to large programs, using tools like mtrace to diagnose for you where memory is allocated but not deallocated is a wonderful tool to save both your time and sanity. It also allows you to know quantitatively that no memory leaks occur in your code.
Even more importantly, when you plan to package up libraries or sets of functions to be used by other people, you will want to make certain no leaks exist, and such tools are a vital part of checking the quality of the code you release to other people.
Disclaimer
Acadia University and the author claim no responsibility for anything resulting from the use or misuse of information presented here. Read and use at your own risk.
Search Google
Monday, October 29, 2007
Something about mtrace()
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment