Reputation: 492
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
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
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.
MallocStackLogging=1 ./myprogram
leaks --outputGraph=g1 myprogram
; this will save g1.memgraph
fileleaks --outputGraph=g2 myprogram
myprogram
leaks g1.memgraph
or leaks --diffFrom=g1.memgraph g2.memgraph
Upvotes: 2
Reputation: 4055
It took me a while, but once I figured this all out it works great:
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)leaks -atExit
tells me which leaks exist, but not where any leaked allocation came fromleaks -atExit
runs, obviously, at exitSo you have to run MallocStackLogging, pause your program, then run leaks:
Open a terminal and set MallocStackLogging: export MallocStackLogging=1
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
Run your program and wait for it to pause
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
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:
export MallocStackLogging=1
main
function, add the following code right before returning.system("leaks executablename");
.Upvotes: 5