resource leak detection - always enable for debug builds

This commit is contained in:
Vadim Lopatin 2015-02-13 16:22:43 +03:00
parent d34ffd75a1
commit 195a8587be
8 changed files with 96 additions and 54 deletions

View File

@ -153,3 +153,18 @@ synchronized class Log {
log(LogLevel.Fatal, args); log(LogLevel.Fatal, args);
} }
} }
debug {
private static __gshared bool _appShuttingDown = false;
@property bool appShuttingDown() { return _appShuttingDown; }
/// for debug purposes - sets shutdown flag to log widgets not destroyed in time.
void setAppShuttingDownFlag() {
_appShuttingDown = true;
}
}
void onResourceDestroyWhileShutdown(string resourceName, string objname = null) {
Log.e("Resource leak: destroying resource while shutdown! ", resourceName, " ", objname);
}

View File

@ -81,13 +81,13 @@ class DrawBuf : RefCountedObject {
version (USE_OPENGL) { version (USE_OPENGL) {
_id = drawBufIdGenerator++; _id = drawBufIdGenerator++;
} }
debug(resalloc) _instanceCount++; debug _instanceCount++;
} }
debug(resalloc) private static int _instanceCount; debug private static __gshared int _instanceCount;
debug(resalloc) @property static int instanceCount() { return _instanceCount; } debug @property static int instanceCount() { return _instanceCount; }
~this() { ~this() {
debug(resalloc) _instanceCount--; debug _instanceCount--;
clear(); clear();
} }

View File

@ -85,7 +85,7 @@ private class FontFileItem {
} }
private class FreeTypeFontFile { class FreeTypeFontFile {
private string _filename; private string _filename;
private string _faceName; private string _faceName;
private FT_Library _library; private FT_Library _library;
@ -112,6 +112,7 @@ private class FreeTypeFontFile {
@property bool italic() { return _italic; } @property bool italic() { return _italic; }
debug private static __gshared int _instanceCount; debug private static __gshared int _instanceCount;
debug @property static int instanceCount() { return _instanceCount; }
this(FT_Library library, string filename) { this(FT_Library library, string filename) {
_library = library; _library = library;
_filename = filename; _filename = filename;
@ -119,12 +120,14 @@ private class FreeTypeFontFile {
_matrix.yy = 0x10000; _matrix.yy = 0x10000;
_matrix.xy = 0; _matrix.xy = 0;
_matrix.yx = 0; _matrix.yx = 0;
debug(FontResources) Log.d("Created FreeTypeFontFile, count=", ++_instanceCount); debug ++_instanceCount;
debug(FontResources) Log.d("Created FreeTypeFontFile, count=", _instanceCount);
} }
~this() { ~this() {
clear(); clear();
debug(FontResources) Log.d("Destroyed FreeTypeFontFile, count=", --_instanceCount); debug --_instanceCount;
debug(FontResources) Log.d("Destroyed FreeTypeFontFile, count=", _instanceCount);
} }
private static string familyName(FT_Face face) private static string familyName(FT_Face face)
@ -329,25 +332,29 @@ private class FreeTypeFontFile {
} }
/** /**
* Font implementation based on Win32 API system fonts. * Font implementation based on FreeType.
*/ */
class FreeTypeFont : Font { class FreeTypeFont : Font {
private FontFileItem _fontItem; private FontFileItem _fontItem;
private Collection!(FreeTypeFontFile, true) _files; private Collection!(FreeTypeFontFile, true) _files;
debug(resalloc) static int _instanceCount; debug static __gshared int _instanceCount;
debug @property static int instanceCount() { return _instanceCount; }
/// need to call create() after construction to initialize font /// need to call create() after construction to initialize font
this(FontFileItem item, int size) { this(FontFileItem item, int size) {
_fontItem = item; _fontItem = item;
_size = size; _size = size;
_height = size; _height = size;
debug(resalloc) Log.d("Created font, count=", ++_instanceCount); debug ++_instanceCount;
debug(resalloc) Log.d("Created font, count=", _instanceCount);
} }
/// do cleanup /// do cleanup
~this() { ~this() {
clear(); clear();
debug(resalloc) Log.d("Destroyed font, count=", --_instanceCount); debug --_instanceCount;
debug(resalloc) Log.d("Destroyed font, count=", _instanceCount);
} }
private int _size; private int _size;

View File

@ -211,12 +211,16 @@ immutable(ubyte[]) loadResourceBytes(string filename) {
} }
class Drawable : RefCountedObject { class Drawable : RefCountedObject {
//private static int _instanceCount; debug static __gshared int _instanceCount;
debug @property static int instanceCount() { return _instanceCount; }
this() { this() {
debug ++_instanceCount;
//Log.d("Created drawable, count=", ++_instanceCount); //Log.d("Created drawable, count=", ++_instanceCount);
} }
~this() { ~this() {
//Log.d("Destroyed drawable, count=", --_instanceCount); //Log.d("Destroyed drawable, count=", --_instanceCount);
debug --_instanceCount;
} }
abstract void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0); abstract void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0);
@property abstract int width(); @property abstract int width();
@ -329,27 +333,21 @@ class ImageDrawable : Drawable {
protected DrawBufRef _image; protected DrawBufRef _image;
protected bool _tiled; protected bool _tiled;
debug(resalloc) private static int _instanceCount; debug static __gshared int _instanceCount;
debug @property static int instanceCount() { return _instanceCount; }
this(ref DrawBufRef image, bool tiled = false, bool ninePatch = false) { this(ref DrawBufRef image, bool tiled = false, bool ninePatch = false) {
_image = image; _image = image;
_tiled = tiled; _tiled = tiled;
if (ninePatch) if (ninePatch)
_image.detectNinePatch(); _image.detectNinePatch();
debug(resalloc) { debug _instanceCount++;
_instanceCount++; debug(resalloc) Log.d("Created ImageDrawable, count=", _instanceCount);
Log.d("Created ImageDrawable, count=", _instanceCount);
}
} }
debug(resalloc) {
@property static int instanceCount() { return _instanceCount; }
}
~this() { ~this() {
_image.clear(); _image.clear();
debug(resalloc) { debug _instanceCount--;
_instanceCount--; debug(resalloc) Log.d("Destroyed ImageDrawable, count=", _instanceCount);
Log.d("Destroyed ImageDrawable, count=", _instanceCount);
}
} }
@property override int width() { @property override int width() {
if (_image.isNull) if (_image.isNull)
@ -857,20 +855,23 @@ class DrawableCache {
DrawableRef _drawable; DrawableRef _drawable;
DrawableRef[ColorTransform] _transformed; DrawableRef[ColorTransform] _transformed;
debug(resalloc) private static int _instanceCount; debug private static __gshared int _instanceCount;
debug @property static int instanceCount() { return _instanceCount; }
this(string id, string filename, bool tiled) { this(string id, string filename, bool tiled) {
_id = id; _id = id;
_filename = filename; _filename = filename;
_tiled = tiled; _tiled = tiled;
_error = filename is null; _error = filename is null;
debug(resalloc) Log.d("Created DrawableCacheItem, count=", ++_instanceCount); debug ++_instanceCount;
debug(resalloc) Log.d("Created DrawableCacheItem, count=", _instanceCount);
} }
~this() { ~this() {
_drawable.clear(); _drawable.clear();
foreach(ref t; _transformed) foreach(ref t; _transformed)
t.clear(); t.clear();
_transformed.destroy(); _transformed.destroy();
debug(resalloc) Log.d("Destroyed DrawableCacheItem, count=", --_instanceCount); debug --_instanceCount;
debug(resalloc) Log.d("Destroyed DrawableCacheItem, count=", _instanceCount);
} }
/// remove from memory, will cause reload on next access /// remove from memory, will cause reload on next access
void compact() { void compact() {

View File

@ -873,6 +873,7 @@ class SDLPlatform : Platform {
Log.i("entering message loop"); Log.i("entering message loop");
SDL_Event event; SDL_Event event;
bool quit = false; bool quit = false;
bool skipNextQuit = false;
while(!quit) { while(!quit) {
//redrawWindows(); //redrawWindows();
@ -882,9 +883,12 @@ class SDLPlatform : Platform {
//Log.d("Event.type = ", event.type); //Log.d("Event.type = ", event.type);
if (event.type == SDL_QUIT) { if (event.type == SDL_QUIT) {
Log.i("event.type == SDL_QUIT"); if (!skipNextQuit) {
quit = true; Log.i("event.type == SDL_QUIT");
break; quit = true;
break;
}
skipNextQuit = false;
} }
if (_redrawEventId && event.type == _redrawEventId) { if (_redrawEventId && event.type == _redrawEventId) {
// user defined redraw event // user defined redraw event
@ -920,9 +924,13 @@ class SDLPlatform : Platform {
w.redraw(); w.redraw();
break; break;
case SDL_WINDOWEVENT_CLOSE: case SDL_WINDOWEVENT_CLOSE:
debug(DebugSDL) Log.d("SDL_WINDOWEVENT_CLOSE win=", event.window.windowID); if (w.handleCanClose()) {
_windowMap.remove(windowID); debug(DebugSDL) Log.d("SDL_WINDOWEVENT_CLOSE win=", event.window.windowID);
destroy(w); _windowMap.remove(windowID);
destroy(w);
} else {
skipNextQuit = true;
}
break; break;
case SDL_WINDOWEVENT_SHOWN: case SDL_WINDOWEVENT_SHOWN:
debug(DebugSDL) Log.d("SDL_WINDOWEVENT_SHOWN"); debug(DebugSDL) Log.d("SDL_WINDOWEVENT_SHOWN");
@ -1344,15 +1352,13 @@ int sdlmain(string[] args) {
Platform.setInstance(null); Platform.setInstance(null);
// //
debug(resalloc) { debug setAppShuttingDownFlag();
Widget.shuttingDown();
}
currentTheme = null; currentTheme = null;
drawableCache = null; drawableCache = null;
imageCache = null; imageCache = null;
FontManager.instance = null; FontManager.instance = null;
debug(resalloc) { debug {
if (DrawBuf.instanceCount > 0) { if (DrawBuf.instanceCount > 0) {
Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount); Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount);
} }
@ -1365,6 +1371,14 @@ int sdlmain(string[] args) {
if (ImageDrawable.instanceCount > 0) { if (ImageDrawable.instanceCount > 0) {
Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount); Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount);
} }
version (USE_FREETYPE) {
if (FreeTypeFontFile.instanceCount > 0) {
Log.e("Non-zero FreeTypeFontFile instance count when exiting: ", FreeTypeFontFile.instanceCount);
}
if (FreeTypeFont.instanceCount > 0) {
Log.e("Non-zero FreeTypeFont instance count when exiting: ", FreeTypeFont.instanceCount);
}
}
} }
Log.d("Exiting main"); Log.d("Exiting main");

View File

@ -150,6 +150,9 @@ class ComboBoxBase : HorizontalLayout, OnClickHandler {
addChild(_body); addChild(_body);
addChild(_button); addChild(_button);
} }
~this() {
}
} }
@ -234,6 +237,13 @@ class ComboBox : ComboBoxBase {
return res; return res;
} }
~this() {
if (_adapter) {
destroy(_adapter);
_adapter = null;
}
}
} }
/** Editable ComboBox with list of strings. */ /** Editable ComboBox with list of strings. */

View File

@ -699,14 +699,14 @@ class Style {
return this; return this;
} }
debug(resalloc) private static int _instanceCount; debug private static __gshared int _instanceCount;
debug(resalloc) @property static int instanceCount() { return _instanceCount; } debug @property static int instanceCount() { return _instanceCount; }
this(Theme theme, string id) { this(Theme theme, string id) {
_theme = theme; _theme = theme;
_parentStyle = theme; _parentStyle = theme;
_id = id; _id = id;
debug(resalloc) _instanceCount++; debug _instanceCount++;
//Log.d("Created style ", _id, ", count=", ++_instanceCount); //Log.d("Created style ", _id, ", count=", ++_instanceCount);
} }
@ -725,7 +725,7 @@ class Style {
_children.destroy(); _children.destroy();
_backgroundDrawable.clear(); _backgroundDrawable.clear();
_font.clear(); _font.clear();
debug(resalloc) _instanceCount--; debug _instanceCount--;
//Log.d("Destroyed style ", _id, ", parentId=", _parentId, ", state=", _stateMask, ", count=", --_instanceCount); //Log.d("Destroyed style ", _id, ", parentId=", _parentId, ", state=", _stateMask, ", count=", --_instanceCount);
} }

View File

@ -174,9 +174,8 @@ class Widget {
return CursorType.Arrow; return CursorType.Arrow;
} }
debug(resalloc) { debug {
private static int _instanceCount = 0; private static __gshared int _instanceCount = 0;
private static bool _appShuttingDown = false;
} }
/// empty parameter list constructor - for usage by factory /// empty parameter list constructor - for usage by factory
this() { this() {
@ -186,15 +185,15 @@ class Widget {
this(string ID) { this(string ID) {
_id = ID; _id = ID;
_state = State.Enabled; _state = State.Enabled;
debug(resalloc) _instanceCount++; debug _instanceCount++;
//Log.d("Created widget, count = ", ++_instanceCount); //Log.d("Created widget, count = ", ++_instanceCount);
} }
~this() { ~this() {
debug(resalloc) { debug {
//Log.v("destroying widget ", _id); //Log.v("destroying widget ", _id, " ", this.classinfo.name);
if (_appShuttingDown) if (appShuttingDown)
Log.e("Destroying widget ", _id, " after app shutdown: probably, resource leak"); onResourceDestroyWhileShutdown(_id, this.classinfo.name);
_instanceCount--; _instanceCount--;
} }
if (_ownStyle !is null) if (_ownStyle !is null)
@ -203,13 +202,9 @@ class Widget {
//Log.d("Destroyed widget, count = ", --_instanceCount); //Log.d("Destroyed widget, count = ", --_instanceCount);
} }
debug(resalloc) { debug {
/// for debug purposes - number of created widget objects, not yet destroyed /// for debug purposes - number of created widget objects, not yet destroyed
static @property int instanceCount() { return _instanceCount; } static @property int instanceCount() { return _instanceCount; }
/// for debug purposes - sets shutdown flag to log widgets not destroyed in time.
static void shuttingDown() {
_appShuttingDown = true;
}
} }
/// accessor to style - by lookup in theme by styleId (if style id is not set, theme base style will be used). /// accessor to style - by lookup in theme by styleId (if style id is not set, theme base style will be used).