OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef BASE_LEAK_TRACKER_H_ | |
6 #define BASE_LEAK_TRACKER_H_ | |
7 #pragma once | |
8 | |
9 // Only enable leak tracking in debug builds. | |
10 #ifndef NDEBUG | |
11 #define ENABLE_LEAK_TRACKER | |
12 #endif | |
13 | |
14 #ifdef ENABLE_LEAK_TRACKER | |
15 #include "base/debug_util.h" | |
16 #include "base/linked_list.h" | |
17 #include "base/logging.h" | |
18 #endif // ENABLE_LEAK_TRACKER | |
19 | |
20 // LeakTracker is a helper to verify that all instances of a class | |
21 // have been destroyed. | |
22 // | |
23 // It is particularly useful for classes that are bound to a single thread -- | |
24 // before destroying that thread, one can check that there are no remaining | |
25 // instances of that class. | |
26 // | |
27 // For example, to enable leak tracking for class URLRequest, start by | |
28 // adding a member variable of type LeakTracker<URLRequest>. | |
29 // | |
30 // class URLRequest { | |
31 // ... | |
32 // private: | |
33 // base::LeakTracker<URLRequest> leak_tracker_; | |
34 // }; | |
35 // | |
36 // | |
37 // Next, when we believe all instances of URLRequest have been deleted: | |
38 // | |
39 // LeakTracker<URLRequest>::CheckForLeaks(); | |
40 // | |
41 // Should the check fail (because there are live instances of URLRequest), | |
42 // then the allocation callstack for each leaked instances is dumped to | |
43 // the error log. | |
44 // | |
45 // If ENABLE_LEAK_TRACKER is not defined, then the check has no effect. | |
46 | |
47 namespace base { | |
48 | |
49 #ifndef ENABLE_LEAK_TRACKER | |
50 | |
51 // If leak tracking is disabled, do nothing. | |
52 template<typename T> | |
53 class LeakTracker { | |
54 public: | |
55 static void CheckForLeaks() {} | |
56 static int NumLiveInstances() { return -1; } | |
57 }; | |
58 | |
59 #else | |
60 | |
61 // If leak tracking is enabled we track where the object was allocated from. | |
62 | |
63 template<typename T> | |
64 class LeakTracker : public LinkNode<LeakTracker<T> > { | |
65 public: | |
66 LeakTracker() { | |
67 instances()->Append(this); | |
68 } | |
69 | |
70 ~LeakTracker() { | |
71 this->RemoveFromList(); | |
72 } | |
73 | |
74 static void CheckForLeaks() { | |
75 // Walk the allocation list and print each entry it contains. | |
76 size_t count = 0; | |
77 | |
78 // Copy the first 3 leak allocation callstacks onto the stack. | |
79 // This way if we hit the CHECK() in a release build, the leak | |
80 // information will be available in mini-dump. | |
81 const size_t kMaxStackTracesToCopyOntoStack = 3; | |
82 StackTrace stacktraces[kMaxStackTracesToCopyOntoStack]; | |
83 | |
84 for (LinkNode<LeakTracker<T> >* node = instances()->head(); | |
85 node != instances()->end(); | |
86 node = node->next()) { | |
87 StackTrace& allocation_stack = node->value()->allocation_stack_; | |
88 | |
89 if (count < kMaxStackTracesToCopyOntoStack) | |
90 stacktraces[count] = allocation_stack; | |
91 | |
92 ++count; | |
93 LOG(ERROR) << "Leaked " << node << " which was allocated by:"; | |
94 allocation_stack.OutputToStream(&LOG_STREAM(ERROR)); | |
95 } | |
96 | |
97 CHECK_EQ(0u, count); | |
98 | |
99 // Hack to keep |stacktraces| and |count| alive (so compiler | |
100 // doesn't optimize it out, and it will appear in mini-dumps). | |
101 if (count == 0x1234) { | |
102 for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i) | |
103 stacktraces[i].PrintBacktrace(); | |
104 } | |
105 } | |
106 | |
107 static int NumLiveInstances() { | |
108 // Walk the allocation list and count how many entries it has. | |
109 int count = 0; | |
110 for (LinkNode<LeakTracker<T> >* node = instances()->head(); | |
111 node != instances()->end(); | |
112 node = node->next()) { | |
113 ++count; | |
114 } | |
115 return count; | |
116 } | |
117 | |
118 private: | |
119 // Each specialization of LeakTracker gets its own static storage. | |
120 static LinkedList<LeakTracker<T> >* instances() { | |
121 static LinkedList<LeakTracker<T> > list; | |
122 return &list; | |
123 } | |
124 | |
125 StackTrace allocation_stack_; | |
126 }; | |
127 | |
128 #endif // ENABLE_LEAK_TRACKER | |
129 | |
130 } // namespace base | |
131 | |
132 #endif // BASE_LEAK_TRACKER_H_ | |
OLD | NEW |