Browse Source

Added a new HeavyweightLeakedObjectDetector to juce_core which will print out a stack trace showing where the leaked object was created and added a corresponding JUCE_HEAVYWEIGHT_LEAK_DETECTOR macro

tags/2021-05-28
ed 7 years ago
parent
commit
d56e4c3cc3
2 changed files with 145 additions and 0 deletions
  1. +1
    -0
      modules/juce_core/juce_core.h
  2. +144
    -0
      modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.h

+ 1
- 0
modules/juce_core/juce_core.h View File

@@ -338,6 +338,7 @@ namespace juce
#include "zip/juce_ZipFile.h"
#include "containers/juce_PropertySet.h"
#include "memory/juce_SharedResourcePointer.h"
#include "memory/juce_HeavyweightLeakedObjectDetector.h"
#if JUCE_CORE_INCLUDE_OBJC_HELPERS && (JUCE_MAC || JUCE_IOS)
#include "native/juce_osx_ObjCHelpers.h"


+ 144
- 0
modules/juce_core/memory/juce_HeavyweightLeakedObjectDetector.h View File

@@ -0,0 +1,144 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
The code included in this file is provided under the terms of the ISC license
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
To use, copy, modify, and/or distribute this software for any purpose with or
without fee is hereby granted provided that the above copyright notice and
this permission notice appear in all copies.
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
/**
This class is a useful way of tracking down hard to find memory leaks when the
regular LeakedObjectDetector isn't enough.
As well as firing when any instances of the OwnerClass type are leaked, it will
print out a stack trace showing where the leaked object was created. This is obviously
quite a heavyweight task so, unlike the LeakedObjectDetector which should be always
be added to your classes, you should only use this object temporarily when you are
debugging and remove it when finished.
To use it, use the JUCE_HEAVYWEIGHT_LEAK_DETECTOR macro as a simple way to put
one in your class declaration.
@tags{Core}
*/
template <class OwnerClass>
class HeavyweightLeakedObjectDetector
{
public:
//==============================================================================
HeavyweightLeakedObjectDetector() noexcept { getBacktraceMap().set (this, SystemStats::getStackBacktrace()); }
HeavyweightLeakedObjectDetector (const HeavyweightLeakedObjectDetector&) noexcept { getBacktraceMap().set (this, SystemStats::getStackBacktrace()); }
~HeavyweightLeakedObjectDetector() { getBacktraceMap().remove (this); }
private:
//==============================================================================
typedef HashMap<HeavyweightLeakedObjectDetector<OwnerClass>*, String> BacktraceMap;
//==============================================================================
struct BacktraceMapHolder
{
BacktraceMapHolder() noexcept {}
~BacktraceMapHolder()
{
if (map.size() > 0)
{
DBG ("*** Leaked objects detected: " << map.size() << " instance(s) of class " << getLeakedObjectClassName());
DBG (getFormattedBacktracesString());
/** If you hit this, then you've leaked one or more objects of the type specified by
the 'OwnerClass' template parameter - the name and stack trace of its creation should
have been printed by the lines above.
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use std::unique_ptrs, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
jassertfalse;
}
}
String getFormattedBacktracesString() const
{
String str;
int counter = 1;
for (typename BacktraceMap::Iterator i (map); i.next();)
{
str << "\nBacktrace " << String (counter++) << "\n"
<< "-----------------------------------------------------------------" << "\n"
<< i.getValue();
}
return str;
}
BacktraceMap map;
};
static BacktraceMap& getBacktraceMap()
{
static BacktraceMapHolder holder;
return holder.map;
}
static const char* getLeakedObjectClassName()
{
return OwnerClass::getLeakedObjectClassName();
}
};
//==============================================================================
#if DOXYGEN || ! defined (JUCE_HEAVYWEIGHT_LEAK_DETECTOR)
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
/** This macro lets you embed a heavyweight leak-detecting object inside a class.
To use it, simply declare a JUCE_HEAVYWEIGHT_LEAK_DETECTOR (YourClassName) inside a private section
of the class declaration. E.g.
@code
class MyClass
{
public:
MyClass();
void blahBlah();
private:
JUCE_HEAVYWEIGHT_LEAK_DETECTOR (MyClass)
};
@endcode
NB: you should only use this when you really need to track down a tricky memory leak, and
should never leave one of these inside a class!
@see HeavyweightLeakedObjectDetector, JUCE_LEAK_DETECTOR, LeakedObjectDetector
*/
#define JUCE_HEAVYWEIGHT_LEAK_DETECTOR(OwnerClass) \
friend class juce::HeavyweightLeakedObjectDetector<OwnerClass>; \
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
juce::HeavyweightLeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
#else
#define JUCE_HEAVYWEIGHT_LEAK_DETECTOR(OwnerClass)
#endif
#endif
} // namespace juce

Loading…
Cancel
Save