leak_tracker.h 3.8 KB

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