KIYZ
KIYZ

Reputation: 492

How to use leaks command-line tool to find memory leaks?

leaks command-line tool will report

like the following:

Process:         checker [84357]
Path:            /path/to/program
Load Address:    0x104703000
Identifier:      checker
Version:         ???
Code Type:       X86-64
Parent Process:  zsh [64610]

Date/Time:       2019-11-30 18:43:06.864 -0800
Launch Time:     2019-11-30 18:42:58.593 -0800
OS Version:      Mac OS X 10.13.4 (17E199)
Report Version:  7
Analysis Tool:   /usr/bin/leaks

Physical footprint:         300K
Physical footprint (peak):  300K
----

leaks Report Version: 3.0
Process 84357: 161 nodes malloced for 17 KB
Process 84357: 3 leaks for 64 total leaked bytes.

Leak: 0x7fdf5b400350  size=16  zone: DefaultMallocZone_0x10470e000
Leak: 0x7fdf5b4027c0  size=16  zone: DefaultMallocZone_0x10470e000
Leak: 0x7fdf5b402810  size=32  zone: DefaultMallocZone_0x10470e000

My question is, how can I use these information to actually track down and find which malloc calls in my source code doesn’t have corresponding free() calls?
How can I find out which source file / where in the source file?
Do I need to change the value of some environment variables like MallocStackLogging or MallocStackLoggingNoCompact?

Upvotes: 5

Views: 28259

Answers (4)

Richard Kirk
Richard Kirk

Reputation: 331

tl;dr : leaks -quiet -atExit -- <your_leaky_command>

Here is what I wish I had been told when I started using leaks...

Setting the environment variable MallocStackLogging=1 turns on the stack logging. If you type it at your terminal session, it is hard to turn it off again. Everything will run slow and spew MallocStackLogging messages. Close the tab, and start a fresh one.

In a fresh tab, enter the command...

MallocStackLogging=1 <your_leaky_command>

This gives a bunch of the MallocStackLogging messages as your command executes, but the terminal continues as normal. The effect of setting MallocStackLogging=1 ends with the command line.

We haven't learned anything about the leaks. We need to attach leaks to the command while it runs. The best time is just as it finishes. You can do this with...

MallocStackLogging=1 leaks -atExit -- <your_leaky_command>

This gives you the leak information but it will also gives a torrent of binary stuff you probably cannot use. Try...

MallocStackLogging=1 leaks -quiet -atExit -- <your_leaky_command>

Note: -atExit has to be the last argument.

This is beginning to be useful, but why do we have to set MallocStackLogging=1? Can't leaks do this for us? In fact, if MallocStackLogging is not set when leaks is called, it sets MallocStackLogging=lite which is subtly different but does much the same thing. Your command now is...

leaks -quiet -atExit -- <your_leaky_command>

I still get two MallocStackLogging messages when the leaky command runs. I have not found a way to hide these.

You can call leaks using system() in your application. I do this shortly before exit, and pipe the leaks output to a file. The application then prints out the leaks message in a bright colour if the system() call returned non-zero. This hides all the messages when there are no leaks to report. I run a test script with many calls, and this makes the output much easier to scan.

Upvotes: 0

Michal Moskal
Michal Moskal

Reputation: 31

You can save memory graph file with the leaks command. If malloc stack logging is enabled the graph will include stack traces.

If your program is a long-running process chances are you want to compare memory usage at different point in time, which can be also done with the leaks commands.

  • in one terminal, run you program with stack logging: MallocStackLogging=1 ./myprogram
  • in another terminal, run leaks --outputGraph=g1 myprogram; this will save g1.memgraph file
  • (optional) after some time run leaks --outputGraph=g2 myprogram
  • you can now kill myprogram
  • view the results with either leaks g1.memgraph or leaks --diffFrom=g1.memgraph g2.memgraph

Upvotes: 2

mwag
mwag

Reputation: 4055

It took me a while, but once I figured this all out it works great:

  • I used to use valgrind, until it couldn't run on my newer osx version. I was looking for a similarly convenient command-line approach to tracing memory leaks (could use Instruments instead, but it is heavyweight and UI-driven, both of which annoy me)
  • Using leaks -atExit tells me which leaks exist, but not where any leaked allocation came from
  • MallocStackLogging creates logs that can tell me where the leaked allocations came from, but the logs are automatically deleted when the program exits, and leaks -atExit runs, obviously, at exit

So you have to run MallocStackLogging, pause your program, then run leaks:

  1. Open a terminal and set MallocStackLogging: export MallocStackLogging=1

  2. At the end of the program, before it exists, add a line of code to pause it by reading from stdin, then recompile: fscanf(stdin, "c"); // wait for user to enter input from keyboard

  3. Run your program and wait for it to pause

  4. In a separate terminal, output the leak allocations by running leaks my_program_name (or alternatively, find your pid: ps aux | grep my_program_name and then run leaks <pid>).

Cheers

Upvotes: 9

KIYZ
KIYZ

Reputation: 492

Set environment variable MallocStackLogging to true, run program, then run leaks.
This will print a stack trace of where the leaked memory was allocated.

The way I did it is:

  1. export MallocStackLogging=1
  2. In the main function, add the following code right before returning.
    system("leaks executablename"); .
  3. Run program.

Upvotes: 5

Related Questions