Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_memory_leak_tracker.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
8
9#include <QMutex>
10#include <QMutexLocker>
11#include <QGlobalStatic>
12
13#include "kis_debug.h"
14
15// Those defines are used to ignore classes that are often leaked due to a KisPaintDevice leak
16#define IGNORE_MEMENTO_ITEM
17#define IGNORE_TILE
18
20
21// Common function
23{
24 return s_instance;
25}
26#ifdef HAVE_MEMORY_LEAK_TRACKER
27
28#include <QHash>
29
30#ifdef Q_OS_LINUX
31
32struct BacktraceInfo {
33 BacktraceInfo() : trace(0), size(0) {
34 }
35 ~BacktraceInfo() {
36 delete[] trace;
37 }
38 void** trace;
39 int size;
40};
41
42#define BACKTRACE_SIZE 10
43
44#include <execinfo.h>
45
46#ifdef HAVE_BACKTRACE_SUPPORT
47#define MAKE_BACKTRACEINFO \
48 BacktraceInfo* info = new BacktraceInfo; \
49 info->trace = new void*[BACKTRACE_SIZE]; \
50 int n = backtrace(info->trace, BACKTRACE_SIZE); \
51 info->size = n;
52#else
53#define MAKE_BACKTRACEINFO \
54 BacktraceInfo* info = 0;
55#endif
56
57struct WhatInfo {
58 QHash<const void*, BacktraceInfo*> infos;
59 QString name;
60};
61
62struct KisMemoryLeakTracker::Private {
63 QHash<const void*, WhatInfo > whatWhoWhen;
64 template<typename _T_>
65 void dumpReferencedObjectsAndDelete(QHash<const _T_*, WhatInfo >&, bool _delete);
66 QMutex m;
67};
68
69template<typename _T_>
70void KisMemoryLeakTracker::Private::dumpReferencedObjectsAndDelete(QHash<const _T_*, WhatInfo >& map, bool _delete)
71{
72 QMutexLocker l(&m);
73 for (typename QHash<const _T_*, WhatInfo >::iterator it = map.begin();
74 it != map.end(); ++it) {
75 qWarning() << "Object " << it.key() << "(" << it.value().name << ") is still referenced by " << it.value().infos.size() << " objects:";
76 for (QHash<const void*, BacktraceInfo*>::iterator it2 = it.value().infos.begin();
77 it2 != it.value().infos.end(); ++it2) {
78 qWarning() << "Referenced by " << it2.key() << " at:";
79#ifdef HAVE_BACKTRACE_SUPPORT
80 BacktraceInfo* info = it2.value();
81 char** strings = backtrace_symbols(info->trace, info->size);
82 for (int i = 0; i < info->size; ++i) {
83 qWarning() << strings[i];
84 }
85 if (_delete) {
86 delete info;
87 it2.value() = 0;
88 }
89#else
90 Q_UNUSED(_delete);
91 qWarning() << "Enable backtrace support by running 'cmake -DHAVE_BACKTRACE_SUPPORT=ON'";
92#endif
93 }
94 qWarning() << "=====";
95 }
96}
97
99{
100}
101
103{
104 if (d->whatWhoWhen.isEmpty()) {
105 qInfo() << "No leak detected.";
106 } else {
107 qWarning() << "****************************************";
108 qWarning() << (d->whatWhoWhen.size()) << " leaks have been detected";
109 d->dumpReferencedObjectsAndDelete(d->whatWhoWhen, true);
110 qWarning() << "****************************************";
111#ifndef NDEBUG
112 qFatal("Leaks have been detected... fix krita.");
113#endif
114 }
115 delete d;
116}
117
118void KisMemoryLeakTracker::reference(const void* what, const void* bywho, const char* whatName)
119{
120 if(what == 0x0) return;
121
122 QMutexLocker l(&d->m);
123
124 if (whatName == 0 || ( strcmp(whatName, "PK13KisSharedData") != 0
126 && strcmp(whatName, "PK14KisMementoItem") != 0
127#endif
128#ifdef IGNORE_TILE
129 && strcmp(whatName, "PK7KisTile") != 0
130#endif
131 ) ) {
132 MAKE_BACKTRACEINFO
133 d->whatWhoWhen[what].infos[bywho] = info;
134 if (whatName) {
135 d->whatWhoWhen[what].name = whatName;
136 }
137 }
138}
139
140void KisMemoryLeakTracker::dereference(const void* what, const void* bywho)
141{
142 QMutexLocker l(&d->m);
143 if (d->whatWhoWhen.contains(what)) {
144 QHash<const void*, BacktraceInfo*>& whoWhen = d->whatWhoWhen[what].infos;
145 delete whoWhen[bywho];
146 whoWhen.remove(bywho);
147 if (whoWhen.isEmpty()) {
148 d->whatWhoWhen.remove(what);
149 }
150 }
151}
152
154{
155 qWarning() << "****************************************";
156 qWarning() << (d->whatWhoWhen.size()) << " objects are currently referenced";
157 d->dumpReferencedObjectsAndDelete(d->whatWhoWhen, false);
158 qWarning() << "****************************************";
159}
160
161void KisMemoryLeakTracker::dumpReferences(const void* what)
162{
163 QMutexLocker l(&d->m);
164 if (!d->whatWhoWhen.contains(what)) {
165 qWarning() << "Object " << what << " is not tracked";
166 return;
167 }
168
169 WhatInfo& info = d->whatWhoWhen[what];
170 qInfo() << "Object " << what << "(" << info.name << ") is still referenced by " << info.infos.size() << " objects:";
171 for (QHash<const void*, BacktraceInfo*>::iterator it2 = info.infos.begin();
172 it2 != info.infos.end(); ++it2) {
173 qInfo() << "Referenced by " << it2.key() << " at:";
174#ifdef HAVE_BACKTRACE_SUPPORT
175 BacktraceInfo* info = it2.value();
176 char** strings = backtrace_symbols(info->trace, info->size);
177 for (int i = 0; i < info->size; ++i) {
178 qInfo() << strings[i];
179 }
180#else
181 qInfo() << "Enable backtrace support in kis_memory_leak_tracker.cpp";
182#endif
183 }
184 qInfo() << "=====";
185}
186
187#else
188#error "Hum, no memory leak tracker for your platform"
189#endif
190
191#else
192
196
200
201void KisMemoryLeakTracker::reference(const void* what, const void* bywho, const char* whatName)
202{
203 Q_UNUSED(what);
204 Q_UNUSED(bywho);
205 Q_UNUSED(whatName);
206}
207
208void KisMemoryLeakTracker::dereference(const void* what, const void* bywho)
209{
210 Q_UNUSED(what);
211 Q_UNUSED(bywho);
212}
213
217
219{
220 Q_UNUSED(what);
221}
222
223#endif
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
PythonPluginManager * instance
void dereference(const void *what, const void *bywho)
void reference(const void *what, const void *bywho, const char *whatName=0)
#define IGNORE_MEMENTO_ITEM
#define IGNORE_TILE
const char * name(StandardAction id)
int size(const Forest< T > &forest)
Definition KisForest.h:1232