1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
|
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
* @class vtkDebugLeaks
* @brief identify memory leaks at program termination
* vtkDebugLeaks is used to report memory leaks at the exit of the program. It
* uses vtkObjectBase::InitializeObjectBase() (called via vtkObjectFactory
* macros) to intercept the construction of all VTK objects. It uses the
* UnRegisterInternal method of vtkObjectBase to intercept the destruction of
* all objects.
*
* If not using the vtkObjectFactory macros to implement New(), be sure to call
* vtkObjectBase::InitializeObjectBase() explicitly on the constructed
* instance. The rule of thumb is that wherever "new [some vtkObjectBase
* subclass]" is called, vtkObjectBase::InitializeObjectBase() must be called
* as well.
*
* There are exceptions to this:
*
* - vtkCommand subclasses traditionally do not fully participate in
* vtkDebugLeaks registration, likely because they typically do not use
* vtkTypeMacro to configure GetClassName. InitializeObjectBase should not be
* called on vtkCommand subclasses, and all such classes will be automatically
* registered with vtkDebugLeaks as "vtkCommand or subclass".
*
* - vtkInformationKey subclasses are not reference counted. They are allocated
* statically and registered automatically with a singleton "manager" instance.
* The manager ensures that all keys are cleaned up before exiting, and
* registration/deregistration with vtkDebugLeaks is bypassed.
*
* A table of object name to number of instances is kept. At the exit of the
* program if there are still VTK objects around it will print them out. To
* enable this class add the flag -DVTK_DEBUG_LEAKS to the compile line, and
* rebuild vtkObject and vtkObjectFactory.
*/
#ifndef vtkDebugLeaks_h
#define vtkDebugLeaks_h
#include "vtkCommonCoreModule.h" // For export macro
#include "vtkObject.h"
#include "vtkDebug.h" // Needed for VTK_DEBUG_LEAKS macro setting.
#include "vtkDebugLeaksManager.h" // Needed for proper singleton initialization
#include <functional> // for finalizers
#include <mutex> // for std::mutex
#include <vector> // for finalizers
VTK_ABI_NAMESPACE_BEGIN
class vtkDebugLeaksHashTable;
class vtkDebugLeaksTraceManager;
class vtkDebugLeaksObserver;
class VTKCOMMONCORE_EXPORT vtkDebugLeaks : public vtkObject
{
public:
static vtkDebugLeaks* New();
vtkTypeMacro(vtkDebugLeaks, vtkObject);
void PrintSelf(ostream& os, vtkIndent indent) override;
/**
* Call this when creating a class.
*/
static void ConstructClass(vtkObjectBase* object);
/**
* Call this when creating a vtkCommand or subclasses.
*/
static void ConstructClass(const char* className);
/**
* Call this when deleting a class.
*/
static void DestructClass(vtkObjectBase* object);
/**
* Call this when deleting vtkCommand or a subclass.
*/
static void DestructClass(const char* className);
/**
* Print all the values in the table. Returns non-zero if there
* were leaks.
*/
static int PrintCurrentLeaks();
///@{
/**
* Get/Set flag for exiting with an error when leaks are present.
* Default is on when VTK_DEBUG_LEAKS is on and off otherwise.
*/
static int GetExitError();
static void SetExitError(int);
///@}
static void SetDebugLeaksObserver(vtkDebugLeaksObserver* observer);
static vtkDebugLeaksObserver* GetDebugLeaksObserver();
/// Ensure that \a finalizer is invoked before debug-leaks accounting is reported.
///
/// If your application holds VTK objects (i.e., instances of classes that inherit
/// vtkObjectBase) for its duration, then adding \a finalizer function that frees
/// them will prevent vtkDebugLeaks from reporting them as dangling references.
/// This can occur if you declare static global variable that owns a reference
/// to a VTK object (i.e., `static vtkNew<X> global;`). Because the order in which
/// static variables are destroyed is not guaranteed, vtkDebugLeaks (which also
/// depends on a static variable's destruction to report leaks at the exit of the
/// application) may be called before these other static globals are destroyed.
///
/// By adding a \a finalizer, you can release these references before leak
/// reporting is performed.
static void AddFinalizer(std::function<void()> finalizer);
protected:
vtkDebugLeaks() = default;
~vtkDebugLeaks() override = default;
static int DisplayMessageBox(const char*);
static void ClassInitialize();
static void ClassFinalize();
static void ConstructingObject(vtkObjectBase* object);
static void DestructingObject(vtkObjectBase* object);
static std::vector<std::function<void()>>* Finalizers;
friend class vtkDebugLeaksManager;
friend class vtkObjectBase;
private:
static vtkDebugLeaksHashTable* MemoryTable;
static vtkDebugLeaksTraceManager* TraceManager;
static std::mutex* CriticalSection;
static vtkDebugLeaksObserver* Observer;
static int ExitError;
vtkDebugLeaks(const vtkDebugLeaks&) = delete;
void operator=(const vtkDebugLeaks&) = delete;
};
// This class defines callbacks for debugging tools. The callbacks are not for general use.
// The objects passed as arguments to the callbacks are in partially constructed or destructed
// state and accessing them may cause undefined behavior.
class VTKCOMMONCORE_EXPORT vtkDebugLeaksObserver
{
public:
virtual ~vtkDebugLeaksObserver() = default;
virtual void ConstructingObject(vtkObjectBase*) = 0;
virtual void DestructingObject(vtkObjectBase*) = 0;
};
VTK_ABI_NAMESPACE_END
#endif // vtkDebugLeaks_h
|