123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
- <HTML>
- <HEAD>
- <link rel="stylesheet" href="designstyle.css">
- <title>Gperftools Heap Leak Checker</title>
- </HEAD>
- <BODY>
- <p align=right>
- <i>Last modified
- <script type=text/javascript>
- var lm = new Date(document.lastModified);
- document.write(lm.toDateString());
- </script></i>
- </p>
- <p>This is the heap checker we use at Google to detect memory leaks in
- C++ programs. There are three parts to using it: linking the library
- into an application, running the code, and analyzing the output.</p>
- <H1>Linking in the Library</H1>
- <p>The heap-checker is part of tcmalloc, so to install the heap
- checker into your executable, add <code>-ltcmalloc</code> to the
- link-time step for your executable. Also, while we don't necessarily
- recommend this form of usage, it's possible to add in the profiler at
- run-time using <code>LD_PRELOAD</code>:</p>
- <pre>% env LD_PRELOAD="/usr/lib/libtcmalloc.so" <binary></pre>
- <p>This does <i>not</i> turn on heap checking; it just inserts the
- code. For that reason, it's practical to just always link
- <code>-ltcmalloc</code> into a binary while developing; that's what we
- do at Google. (However, since any user can turn on the profiler by
- setting an environment variable, it's not necessarily recommended to
- install heapchecker-linked binaries into a production, running
- system.) Note that if you wish to use the heap checker, you must
- also use the tcmalloc memory-allocation library. There is no way
- currently to use the heap checker separate from tcmalloc.</p>
- <h1>Running the Code</h1>
- <p>Note: For security reasons, heap profiling will not write to a file
- -- and is thus not usable -- for setuid programs.</p>
- <h2><a name="whole_program">Whole-program Heap Leak Checking</a></h2>
- <p>The recommended way to use the heap checker is in "whole program"
- mode. In this case, the heap-checker starts tracking memory
- allocations before the start of <code>main()</code>, and checks again
- at program-exit. If it finds any memory leaks -- that is, any memory
- not pointed to by objects that are still "live" at program-exit -- it
- aborts the program (via <code>exit(1)</code>) and prints a message
- describing how to track down the memory leak (using <A
- HREF="heapprofile.html#pprof">pprof</A>).</p>
- <p>The heap-checker records the stack trace for each allocation while
- it is active. This causes a significant increase in memory usage, in
- addition to slowing your program down.</p>
- <p>Here's how to run a program with whole-program heap checking:</p>
- <ol>
- <li> <p>Define the environment variable HEAPCHECK to the <A
- HREF="#types">type of heap-checking</A> to do. For instance,
- to heap-check
- <code>/usr/local/bin/my_binary_compiled_with_tcmalloc</code>:</p>
- <pre>% env HEAPCHECK=normal /usr/local/bin/my_binary_compiled_with_tcmalloc</pre>
- </ol>
- <p>No other action is required.</p>
- <p>Note that since the heap-checker uses the heap-profiling framework
- internally, it is not possible to run both the heap-checker and <A
- HREF="heapprofile.html">heap profiler</A> at the same time.</p>
- <h3><a name="types">Flavors of Heap Checking</a></h3>
- <p>These are the legal values when running a whole-program heap
- check:</p>
- <ol>
- <li> <code>minimal</code>
- <li> <code>normal</code>
- <li> <code>strict</code>
- <li> <code>draconian</code>
- </ol>
- <p>"Minimal" heap-checking starts as late as possible in a
- initialization, meaning you can leak some memory in your
- initialization routines (that run before <code>main()</code>, say),
- and not trigger a leak message. If you frequently (and purposefully)
- leak data in one-time global initializers, "minimal" mode is useful
- for you. Otherwise, you should avoid it for stricter modes.</p>
- <p>"Normal" heap-checking tracks <A HREF="#live">live objects</A> and
- reports a leak for any data that is not reachable via a live object
- when the program exits.</p>
- <p>"Strict" heap-checking is much like "normal" but has a few extra
- checks that memory isn't lost in global destructors. In particular,
- if you have a global variable that allocates memory during program
- execution, and then "forgets" about the memory in the global
- destructor (say, by setting the pointer to it to NULL) without freeing
- it, that will prompt a leak message in "strict" mode, though not in
- "normal" mode.</p>
- <p>"Draconian" heap-checking is appropriate for those who like to be
- very precise about their memory management, and want the heap-checker
- to help them enforce it. In "draconian" mode, the heap-checker does
- not do "live object" checking at all, so it reports a leak unless
- <i>all</i> allocated memory is freed before program exit. (However,
- you can use <A HREF="#disable">IgnoreObject()</A> to re-enable
- liveness-checking on an object-by-object basis.)</p>
- <p>"Normal" mode, as the name implies, is the one used most often at
- Google. It's appropriate for everyday heap-checking use.</p>
- <p>In addition, there are two other possible modes:</p>
- <ul>
- <li> <code>as-is</code>
- <li> <code>local</code>
- </ul>
- <p><code>as-is</code> is the most flexible mode; it allows you to
- specify the various <A HREF="#options">knobs</A> of the heap checker
- explicitly. <code>local</code> activates the <A
- HREF="#explicit">explicit heap-check instrumentation</A>, but does not
- turn on any whole-program leak checking.</p>
- <h3><A NAME="tweaking">Tweaking whole-program checking</A></h3>
- <p>In some cases you want to check the whole program for memory leaks,
- but waiting for after <code>main()</code> exits to do the first
- whole-program leak check is waiting too long: e.g. in a long-running
- server one might wish to simply periodically check for leaks while the
- server is running. In this case, you can call the static method
- <code>HeapLeakChecker::NoGlobalLeaks()</code>, to verify no global leaks have happened
- as of that point in the program.</p>
- <p>Alternately, doing the check after <code>main()</code> exits might
- be too late. Perhaps you have some objects that are known not to
- clean up properly at exit. You'd like to do the "at exit" check
- before those objects are destroyed (since while they're live, any
- memory they point to will not be considered a leak). In that case,
- you can call <code>HeapLeakChecker::NoGlobalLeaks()</code> manually, near the end of
- <code>main()</code>, and then call <code>HeapLeakChecker::CancelGlobalCheck()</code> to
- turn off the automatic post-<code>main()</code> check.</p>
- <p>Finally, there's a helper macro for "strict" and "draconian" modes,
- which require all global memory to be freed before program exit. This
- freeing can be time-consuming and is often unnecessary, since libc
- cleans up all memory at program-exit for you. If you want the
- benefits of "strict"/"draconian" modes without the cost of all that
- freeing, look at <code>REGISTER_HEAPCHECK_CLEANUP</code> (in
- <code>heap-checker.h</code>). This macro allows you to mark specific
- cleanup code as active only when the heap-checker is turned on.</p>
- <h2><a name="explicit">Explicit (Partial-program) Heap Leak Checking</h2>
- <p>Instead of whole-program checking, you can check certain parts of your
- code to verify they do not have memory leaks. This check verifies that
- between two parts of a program, no memory is allocated without being freed.</p>
- <p>To use this kind of checking code, bracket the code you want
- checked by creating a <code>HeapLeakChecker</code> object at the
- beginning of the code segment, and call
- <code>NoLeaks()</code> at the end. These functions, and all others
- referred to in this file, are declared in
- <code><gperftools/heap-checker.h></code>.
- </p>
- <p>Here's an example:</p>
- <pre>
- HeapLeakChecker heap_checker("test_foo");
- {
- code that exercises some foo functionality;
- this code should not leak memory;
- }
- if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");
- </pre>
- <p>Note that adding in the <code>HeapLeakChecker</code> object merely
- instruments the code for leak-checking. To actually turn on this
- leak-checking on a particular run of the executable, you must still
- run with the heap-checker turned on:</p>
- <pre>% env HEAPCHECK=local /usr/local/bin/my_binary_compiled_with_tcmalloc</pre>
- <p>If you want to do whole-program leak checking in addition to this
- manual leak checking, you can run in <code>normal</code> or some other
- mode instead: they'll run the "local" checks in addition to the
- whole-program check.</p>
- <h2><a name="disable">Disabling Heap-checking of Known Leaks</a></h2>
- <p>Sometimes your code has leaks that you know about and are willing
- to accept. You would like the heap checker to ignore them when
- checking your program. You can do this by bracketing the code in
- question with an appropriate heap-checking construct:</p>
- <pre>
- ...
- {
- HeapLeakChecker::Disabler disabler;
- <leaky code>
- }
- ...
- </pre>
- Any objects allocated by <code>leaky code</code> (including inside any
- routines called by <code>leaky code</code>) and any objects reachable
- from such objects are not reported as leaks.
- <p>Alternately, you can use <code>IgnoreObject()</code>, which takes a
- pointer to an object to ignore. That memory, and everything reachable
- from it (by following pointers), is ignored for the purposes of leak
- checking. You can call <code>UnIgnoreObject()</code> to undo the
- effects of <code>IgnoreObject()</code>.</p>
- <h2><a name="options">Tuning the Heap Checker</h2>
- <p>The heap leak checker has many options, some that trade off running
- time and accuracy, and others that increase the sensitivity at the
- risk of returning false positives. For most uses, the range covered
- by the <A HREF="#types">heap-check flavors</A> is enough, but in
- specialized cases more control can be helpful.</p>
- <p>
- These options are specified via environment varaiables.
- </p>
- <p>This first set of options controls sensitivity and accuracy. These
- options are ignored unless you run the heap checker in <A
- HREF="#types">as-is</A> mode.
- <table frame=box rules=sides cellpadding=5 width=100%>
- <tr valign=top>
- <td><code>HEAP_CHECK_AFTER_DESTRUCTORS</code></td>
- <td>Default: false</td>
- <td>
- When true, do the final leak check after all other global
- destructors have run. When false, do it after all
- <code>REGISTER_HEAPCHECK_CLEANUP</code>, typically much earlier in
- the global-destructor process.
- </td>
- </tr>
- <tr valign=top>
- <td><code>HEAP_CHECK_IGNORE_THREAD_LIVE</code></td>
- <td>Default: true</td>
- <td>
- If true, ignore objects reachable from thread stacks and registers
- (that is, do not report them as leaks).
- </td>
- </tr>
- <tr valign=top>
- <td><code>HEAP_CHECK_IGNORE_GLOBAL_LIVE</code></td>
- <td>Default: true</td>
- <td>
- If true, ignore objects reachable from global variables and data
- (that is, do not report them as leaks).
- </td>
- </tr>
- </table>
- <p>These options modify the behavior of whole-program leak
- checking.</p>
- <table frame=box rules=sides cellpadding=5 width=100%>
- <tr valign=top>
- <td><code>HEAP_CHECK_MAX_LEAKS</code></td>
- <td>Default: 20</td>
- <td>
- The maximum number of leaks to be printed to stderr (all leaks are still
- emitted to file output for pprof to visualize). If negative or zero,
- print all the leaks found.
- </td>
- </tr>
- </table>
- <p>These options apply to all types of leak checking.</p>
- <table frame=box rules=sides cellpadding=5 width=100%>
- <tr valign=top>
- <td><code>HEAP_CHECK_IDENTIFY_LEAKS</code></td>
- <td>Default: false</td>
- <td>
- If true, generate the addresses of the leaked objects in the
- generated memory leak profile files.
- </td>
- </tr>
- <tr valign=top>
- <td><code>HEAP_CHECK_TEST_POINTER_ALIGNMENT</code></td>
- <td>Default: false</td>
- <td>
- If true, check all leaks to see if they might be due to the use
- of unaligned pointers.
- </td>
- </tr>
- <tr valign=top>
- <td><code>HEAP_CHECK_POINTER_SOURCE_ALIGNMENT</code></td>
- <td>Default: sizeof(void*)</td>
- <td>
- Alignment at which all pointers in memory are supposed to be located.
- Use 1 if any alignment is ok.
- </td>
- </tr>
- <tr valign=top>
- <td><code>PPROF_PATH</code></td>
- <td>Default: pprof</td>
- <td>
- The location of the <code>pprof</code> executable.
- </td>
- </tr>
- <tr valign=top>
- <td><code>HEAP_CHECK_DUMP_DIRECTORY</code></td>
- <td>Default: /tmp</td>
- <td>
- Where the heap-profile files are kept while the program is running.
- </td>
- </tr>
- </table>
- <h2>Tips for Handling Detected Leaks</h2>
- <p>What do you do when the heap leak checker detects a memory leak?
- First, you should run the reported <code>pprof</code> command;
- hopefully, that is enough to track down the location where the leak
- occurs.</p>
- <p>If the leak is a real leak, you should fix it!</p>
- <p>If you are sure that the reported leaks are not dangerous and there
- is no good way to fix them, then you can use
- <code>HeapLeakChecker::Disabler</code> and/or
- <code>HeapLeakChecker::IgnoreObject()</code> to disable heap-checking
- for certain parts of the codebase.</p>
- <p>In "strict" or "draconian" mode, leaks may be due to incomplete
- cleanup in the destructors of global variables. If you don't wish to
- augment the cleanup routines, but still want to run in "strict" or
- "draconian" mode, consider using <A
- HREF="#tweaking"><code>REGISTER_HEAPCHECK_CLEANUP</code></A>.</p>
- <h2>Hints for Debugging Detected Leaks</h2>
- <p>Sometimes it can be useful to not only know the exact code that
- allocates the leaked objects, but also the addresses of the leaked objects.
- Combining this e.g. with additional logging in the program
- one can then track which subset of the allocations
- made at a certain spot in the code are leaked.
- <br/>
- To get the addresses of all leaked objects
- define the environment variable <code>HEAP_CHECK_IDENTIFY_LEAKS</code>
- to be <code>1</code>.
- The object addresses will be reported in the form of addresses
- of fake immediate callers of the memory allocation routines.
- Note that the performance of doing leak-checking in this mode
- can be noticeably worse than the default mode.
- </p>
- <p>One relatively common class of leaks that don't look real
- is the case of multiple initialization.
- In such cases the reported leaks are typically things that are
- linked from some global objects,
- which are initialized and say never modified again.
- The non-obvious cause of the leak is frequently the fact that
- the initialization code for these objects executes more than once.
- <br/>
- E.g. if the code of some <code>.cc</code> file is made to be included twice
- into the binary, then the constructors for global objects defined in that file
- will execute twice thus leaking the things allocated on the first run.
- <br/>
- Similar problems can occur if object initialization is done more explicitly
- e.g. on demand by a slightly buggy code
- that does not always ensure only-once initialization.
- </p>
- <p>
- A more rare but even more puzzling problem can be use of not properly
- aligned pointers (maybe inside of not properly aligned objects).
- Normally such pointers are not followed by the leak checker,
- hence the objects reachable only via such pointers are reported as leaks.
- If you suspect this case
- define the environment variable <code>HEAP_CHECK_TEST_POINTER_ALIGNMENT</code>
- to be <code>1</code>
- and then look closely at the generated leak report messages.
- </p>
- <h1>How It Works</h1>
- <p>When a <code>HeapLeakChecker</code> object is constructed, it dumps
- a memory-usage profile named
- <code><prefix>.<name>-beg.heap</code> to a temporary
- directory. When <code>NoLeaks()</code>
- is called (for whole-program checking, this happens automatically at
- program-exit), it dumps another profile, named
- <code><prefix>.<name>-end.heap</code>.
- (<code><prefix></code> is typically determined automatically,
- and <code><name></code> is typically <code>argv[0]</code>.) It
- then compares the two profiles. If the second profile shows
- more memory use than the first, the
- <code>NoLeaks()</code> function will
- return false. For "whole program" profiling, this will cause the
- executable to abort (via <code>exit(1)</code>). In all cases, it will
- print a message on how to process the dumped profiles to locate
- leaks.</p>
- <h3><A name=live>Detecting Live Objects</A></h3>
- <p>At any point during a program's execution, all memory that is
- accessible at that time is considered "live." This includes global
- variables, and also any memory that is reachable by following pointers
- from a global variable. It also includes all memory reachable from
- the current stack frame and from current CPU registers (this captures
- local variables). Finally, it includes the thread equivalents of
- these: thread-local storage and thread heaps, memory reachable from
- thread-local storage and thread heaps, and memory reachable from
- thread CPU registers.</p>
- <p>In all modes except "draconian," live memory is not
- considered to be a leak. We detect this by doing a liveness flood,
- traversing pointers to heap objects starting from some initial memory
- regions we know to potentially contain live pointer data. Note that
- this flood might potentially not find some (global) live data region
- to start the flood from. If you find such, please file a bug.</p>
- <p>The liveness flood attempts to treat any properly aligned byte
- sequences as pointers to heap objects and thinks that it found a good
- pointer whenever the current heap memory map contains an object with
- the address whose byte representation we found. Some pointers into
- not-at-start of object will also work here.</p>
- <p>As a result of this simple approach, it's possible (though
- unlikely) for the flood to be inexact and occasionally result in
- leaked objects being erroneously determined to be live. For instance,
- random bit patterns can happen to look like pointers to leaked heap
- objects. More likely, stale pointer data not corresponding to any
- live program variables can be still present in memory regions,
- especially in thread stacks. For instance, depending on how the local
- <code>malloc</code> is implemented, it may reuse a heap object
- address:</p>
- <pre>
- char* p = new char[1]; // new might return 0x80000000, say.
- delete p;
- new char[1]; // new might return 0x80000000 again
- // This last new is a leak, but doesn't seem it: p looks like it points to it
- </pre>
- <p>In other words, imprecisions in the liveness flood mean that for
- any heap leak check we might miss some memory leaks. This means that
- for local leak checks, we might report a memory leak in the local
- area, even though the leak actually happened before the
- <code>HeapLeakChecker</code> object was constructed. Note that for
- whole-program checks, a leak report <i>does</i> always correspond to a
- real leak (since there's no "before" to have created a false-live
- object).</p>
- <p>While this liveness flood approach is not very portable and not
- 100% accurate, it works in most cases and saves us from writing a lot
- of explicit clean up code and other hassles when dealing with thread
- data.</p>
- <h3>Visualizing Leak with <code>pprof</code></h3>
- <p>
- The heap checker automatically prints basic leak info with stack traces of
- leaked objects' allocation sites, as well as a pprof command line that can be
- used to visualize the call-graph involved in these allocations.
- The latter can be much more useful for a human
- to see where/why the leaks happened, especially if the leaks are numerous.
- </p>
- <h3>Leak-checking and Threads</h3>
- <p>At the time of HeapLeakChecker's construction and during
- <code>NoLeaks()</code> calls, we grab a lock
- and then pause all other threads so other threads do not interfere
- with recording or analyzing the state of the heap.</p>
- <p>In general, leak checking works correctly in the presence of
- threads. However, thread stack data liveness determination (via
- <code>base/thread_lister.h</code>) does not work when the program is
- running under GDB, because the ptrace functionality needed for finding
- threads is already hooked to by GDB. Conversely, leak checker's
- ptrace attempts might also interfere with GDB. As a result, GDB can
- result in potentially false leak reports. For this reason, the
- heap-checker turns itself off when running under GDB.</p>
- <p>Also, <code>thread_lister</code> only works for Linux pthreads;
- leak checking is unlikely to handle other thread implementations
- correctly.</p>
- <p>As mentioned in the discussion of liveness flooding, thread-stack
- liveness determination might mis-classify as reachable objects that
- very recently became unreachable (leaked). This can happen when the
- pointers to now-logically-unreachable objects are present in the
- active thread stack frame. In other words, trivial code like the
- following might not produce the expected leak checking outcome
- depending on how the compiled code works with the stack:</p>
- <pre>
- int* foo = new int [20];
- HeapLeakChecker check("a_check");
- foo = NULL;
- // May fail to trigger.
- if (!heap_checker.NoLeaks()) assert(NULL == "heap memory leak");
- </pre>
- <hr>
- <address>Maxim Lifantsev<br>
- <!-- Created: Tue Dec 19 10:43:14 PST 2000 -->
- <!-- hhmts start -->
- Last modified: Fri Jul 13 13:14:33 PDT 2007
- <!-- hhmts end -->
- </address>
- </body>
- </html>
|