diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-26 04:07:50 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-26 04:07:50 +0000 |
commit | 58580359a452cb7c3b9580edc0843c3ab3d158df (patch) | |
tree | 964dbcc1505f4b9c2bbb5e7a64720861d604c8f3 /base/debug/leak_tracker.h | |
parent | 23872906817de5d402b0c2da6d5f7ee6026378e6 (diff) | |
download | chromium_src-58580359a452cb7c3b9580edc0843c3ab3d158df.zip chromium_src-58580359a452cb7c3b9580edc0843c3ab3d158df.tar.gz chromium_src-58580359a452cb7c3b9580edc0843c3ab3d158df.tar.bz2 |
Move debug-related stuff from base to the base/debug directory and use the
base::debug namespace.
This splits apart debug_util into base/debugger and base/stack_trace
There are still two functions in debug_util that I'm not sure what to do with.
Since this uses the base::debug namespace, I removed the functions in
debugger.h from the static class and just made them free functions in the
namespace.
TEST=it compiles
BUG=none
Review URL: http://codereview.chromium.org/3945002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63859 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/debug/leak_tracker.h')
-rw-r--r-- | base/debug/leak_tracker.h | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h new file mode 100644 index 0000000..8af82a9 --- /dev/null +++ b/base/debug/leak_tracker.h @@ -0,0 +1,134 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_LEAK_TRACKER_H_ +#define BASE_DEBUG_LEAK_TRACKER_H_ +#pragma once + +// Only enable leak tracking in debug builds. +#ifndef NDEBUG +#define ENABLE_LEAK_TRACKER +#endif + +#ifdef ENABLE_LEAK_TRACKER +#include "base/debug/stack_trace.h" +#include "base/linked_list.h" +#include "base/logging.h" +#endif // ENABLE_LEAK_TRACKER + +// LeakTracker is a helper to verify that all instances of a class +// have been destroyed. +// +// It is particularly useful for classes that are bound to a single thread -- +// before destroying that thread, one can check that there are no remaining +// instances of that class. +// +// For example, to enable leak tracking for class URLRequest, start by +// adding a member variable of type LeakTracker<URLRequest>. +// +// class URLRequest { +// ... +// private: +// base::LeakTracker<URLRequest> leak_tracker_; +// }; +// +// +// Next, when we believe all instances of URLRequest have been deleted: +// +// LeakTracker<URLRequest>::CheckForLeaks(); +// +// Should the check fail (because there are live instances of URLRequest), +// then the allocation callstack for each leaked instances is dumped to +// the error log. +// +// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect. + +namespace base { +namespace debug { + +#ifndef ENABLE_LEAK_TRACKER + +// If leak tracking is disabled, do nothing. +template<typename T> +class LeakTracker { + public: + static void CheckForLeaks() {} + static int NumLiveInstances() { return -1; } +}; + +#else + +// If leak tracking is enabled we track where the object was allocated from. + +template<typename T> +class LeakTracker : public LinkNode<LeakTracker<T> > { + public: + LeakTracker() { + instances()->Append(this); + } + + ~LeakTracker() { + this->RemoveFromList(); + } + + static void CheckForLeaks() { + // Walk the allocation list and print each entry it contains. + size_t count = 0; + + // Copy the first 3 leak allocation callstacks onto the stack. + // This way if we hit the CHECK() in a release build, the leak + // information will be available in mini-dump. + const size_t kMaxStackTracesToCopyOntoStack = 3; + StackTrace stacktraces[kMaxStackTracesToCopyOntoStack]; + + for (LinkNode<LeakTracker<T> >* node = instances()->head(); + node != instances()->end(); + node = node->next()) { + StackTrace& allocation_stack = node->value()->allocation_stack_; + + if (count < kMaxStackTracesToCopyOntoStack) + stacktraces[count] = allocation_stack; + + ++count; + LOG(ERROR) << "Leaked " << node << " which was allocated by:"; + allocation_stack.OutputToStream(&LOG_STREAM(ERROR)); + } + + CHECK_EQ(0u, count); + + // Hack to keep |stacktraces| and |count| alive (so compiler + // doesn't optimize it out, and it will appear in mini-dumps). + if (count == 0x1234) { + for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i) + stacktraces[i].PrintBacktrace(); + } + } + + static int NumLiveInstances() { + // Walk the allocation list and count how many entries it has. + int count = 0; + for (LinkNode<LeakTracker<T> >* node = instances()->head(); + node != instances()->end(); + node = node->next()) { + ++count; + } + return count; + } + + private: + // Each specialization of LeakTracker gets its own static storage. + static LinkedList<LeakTracker<T> >* instances() { + static LinkedList<LeakTracker<T> > list; + return &list; + } + + StackTrace allocation_stack_; +}; + +#endif // ENABLE_LEAK_TRACKER + +} // namespace debug +} // namespace base + +#endif // BASE_DEBUG_LEAK_TRACKER_H_ |