fix resource cleanup

This commit is contained in:
Vadim Lopatin 2014-05-05 13:28:22 +04:00
parent b553a7e1d0
commit 300bc90dbf
8 changed files with 135 additions and 73 deletions

View File

@ -41,7 +41,7 @@ import std.algorithm;
/// array based collection of items /// array based collection of items
/// retains item order when during add/remove operations /// retains item order when during add/remove operations
struct Collection(T) { struct Collection(T, bool ownItems = false) {
private T[] _items; private T[] _items;
private size_t _len; private size_t _len;
/// returns true if there are no items in collection /// returns true if there are no items in collection
@ -62,9 +62,12 @@ struct Collection(T) {
// shrink // shrink
static if (is(T == class) || is(T == struct)) { static if (is(T == class) || is(T == struct)) {
// clear items // clear items
for (size_t i = newSize; i < _len; i++) for (size_t i = newSize; i < _len; i++) {
static if (ownItems)
destroy(_items[i]);
_items[i] = T.init; _items[i] = T.init;
} }
}
} else if (newSize > _len) { } else if (newSize > _len) {
// expand // expand
if (_items.length < newSize) if (_items.length < newSize)
@ -130,7 +133,9 @@ struct Collection(T) {
size_t index = indexOf(value); size_t index = indexOf(value);
if (index == size_t.max) if (index == size_t.max)
return false; return false;
remove(index); T res = remove(index);
static if (ownItems)
destroy(res);
return true; return true;
} }
/// support of foreach with reference /// support of foreach with reference
@ -147,9 +152,12 @@ struct Collection(T) {
void clear() { void clear() {
static if (is(T == class) || is(T == struct)) { static if (is(T == class) || is(T == struct)) {
/// clear references /// clear references
for(size_t i = 0; i < _len; i++) for(size_t i = 0; i < _len; i++) {
static if (ownItems)
destroy(_items[i]);
_items[i] = T.init; _items[i] = T.init;
} }
}
_len = 0; _len = 0;
_items = null; _items = null;
} }

View File

@ -138,7 +138,16 @@ class DrawBuf : RefCountedObject {
version (USE_OPENGL) { version (USE_OPENGL) {
_id = drawBufIdGenerator++; _id = drawBufIdGenerator++;
} }
debug(resalloc) _instanceCount++;
} }
debug(resalloc) private static int _instanceCount;
debug(resalloc) @property static int instanceCount() { return _instanceCount; }
~this() {
debug(resalloc) _instanceCount--;
clear();
}
protected void function(uint) _onDestroyCallback; protected void function(uint) _onDestroyCallback;
@property void onDestroyCallback(void function(uint) callback) { _onDestroyCallback = callback; } @property void onDestroyCallback(void function(uint) callback) { _onDestroyCallback = callback; }
@property void function(uint) onDestroyCallback() { return _onDestroyCallback; } @property void function(uint) onDestroyCallback() { return _onDestroyCallback; }
@ -355,7 +364,6 @@ class DrawBuf : RefCountedObject {
} }
void clear() {} void clear() {}
~this() { clear(); }
} }
alias DrawBufRef = Ref!DrawBuf; alias DrawBufRef = Ref!DrawBuf;

View File

@ -5,6 +5,7 @@ import dlangui.graphics.fonts;
import derelict.freetype.ft; import derelict.freetype.ft;
private import dlangui.core.logger; private import dlangui.core.logger;
private import dlangui.core.collections;
private import std.algorithm; private import std.algorithm;
private import std.file; private import std.file;
private import std.string; private import std.string;
@ -99,7 +100,7 @@ private class FreeTypeFontFile {
@property int weight() { return _weight; } @property int weight() { return _weight; }
@property bool italic() { return _italic; } @property bool italic() { return _italic; }
//private static int _instanceCount; debug private static int _instanceCount;
this(FT_Library library, string filename) { this(FT_Library library, string filename) {
_library = library; _library = library;
_filename = filename; _filename = filename;
@ -107,12 +108,12 @@ private class FreeTypeFontFile {
_matrix.yy = 0x10000; _matrix.yy = 0x10000;
_matrix.xy = 0; _matrix.xy = 0;
_matrix.yx = 0; _matrix.yx = 0;
//Log.d("Created FreeTypeFontFile, count=", ++_instanceCount); debug Log.d("Created FreeTypeFontFile, count=", ++_instanceCount);
} }
~this() { ~this() {
clear(); clear();
//Log.d("Destroyed FreeTypeFontFile, count=", --_instanceCount); debug Log.d("Destroyed FreeTypeFontFile, count=", --_instanceCount);
} }
private static string familyName(FT_Face face) private static string familyName(FT_Face face)
@ -292,21 +293,21 @@ private class FreeTypeFontFile {
*/ */
class FreeTypeFont : Font { class FreeTypeFont : Font {
private FontFileItem _fontItem; private FontFileItem _fontItem;
private FreeTypeFontFile[] _files; private Collection!(FreeTypeFontFile, true) _files;
static int _instanceCount; debug(resalloc) static int _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 Log.d("Created font, count=", ++_instanceCount); debug(resalloc) Log.d("Created font, count=", ++_instanceCount);
} }
/// do cleanup /// do cleanup
~this() { ~this() {
clear(); clear();
debug Log.d("Destroyed font, count=", --_instanceCount); debug(resalloc) Log.d("Destroyed font, count=", --_instanceCount);
} }
private int _size; private int _size;
@ -317,10 +318,6 @@ class FreeTypeFont : Font {
/// cleanup resources /// cleanup resources
override void clear() { override void clear() {
foreach(ref FreeTypeFontFile file; _files) {
destroy(file);
file = null;
}
_files.clear(); _files.clear();
} }
@ -375,7 +372,9 @@ class FreeTypeFont : Font {
foreach (string filename; _fontItem.filenames) { foreach (string filename; _fontItem.filenames) {
FreeTypeFontFile file = new FreeTypeFontFile(_fontItem.library, filename); FreeTypeFontFile file = new FreeTypeFontFile(_fontItem.library, filename);
if (file.open(_size, 0)) { if (file.open(_size, 0)) {
_files ~= file; _files.add(file);
} else {
destroy(file);
} }
} }
return _files.length > 0; return _files.length > 0;
@ -503,6 +502,7 @@ class FreeTypeFontManager : FontManager {
weight = font.weight; weight = font.weight;
Log.d("Using properties from font file: face=", face, " weight=", weight, " italic=", italic); Log.d("Using properties from font file: face=", face, " weight=", weight, " italic=", italic);
} }
destroy(font);
FontDef def = FontDef(family, face, italic, weight); FontDef def = FontDef(family, face, italic, weight);
FontFileItem item = findFileItem(def); FontFileItem item = findFileItem(def);

View File

@ -169,17 +169,28 @@ static Drawable createColorDrawable(string s) {
class ImageDrawable : Drawable { class ImageDrawable : Drawable {
protected DrawBufRef _image; protected DrawBufRef _image;
protected bool _tiled; protected bool _tiled;
//private int _instanceCount;
debug(resalloc) private static int _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();
//Log.d("Created ImageDrawable, count=", ++_instanceCount); debug(resalloc) {
_instanceCount++;
Log.d("Created ImageDrawable, count=", _instanceCount);
}
}
debug(resalloc) {
@property static int instanceCount() { return _instanceCount; }
} }
~this() { ~this() {
_image.clear(); _image.clear();
//Log.d("Destroyed ImageDrawable, count=", --_instanceCount); debug(resalloc) {
_instanceCount--;
Log.d("Destroyed ImageDrawable, count=", _instanceCount);
}
} }
@property override int width() { @property override int width() {
if (_image.isNull) if (_image.isNull)
@ -350,7 +361,7 @@ android:state_window_focused=["true" | "false"] />
/// Drawable which is drawn depending on state (see http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList) /// Drawable which is drawn depending on state (see http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList)
class StateDrawable : Drawable { class StateDrawable : Drawable {
static struct StateItem { static class StateItem {
uint stateMask; uint stateMask;
uint stateValue; uint stateValue;
ColorTransform transform; ColorTransform transform;
@ -366,8 +377,14 @@ class StateDrawable : Drawable {
// max drawable size for all states // max drawable size for all states
protected Point _size; protected Point _size;
~this() {
foreach(ref item; _stateList)
destroy(item);
_stateList = null;
}
void addState(uint stateMask, uint stateValue, string resourceId, ref ColorTransform transform) { void addState(uint stateMask, uint stateValue, string resourceId, ref ColorTransform transform) {
StateItem item; StateItem item = new StateItem();
item.stateMask = stateMask; item.stateMask = stateMask;
item.stateValue = stateValue; item.stateValue = stateValue;
item.drawable = drawableCache.get(resourceId, transform); item.drawable = drawableCache.get(resourceId, transform);
@ -375,14 +392,14 @@ class StateDrawable : Drawable {
} }
void addState(uint stateMask, uint stateValue, DrawableRef drawable) { void addState(uint stateMask, uint stateValue, DrawableRef drawable) {
StateItem item; StateItem item = new StateItem();
item.stateMask = stateMask; item.stateMask = stateMask;
item.stateValue = stateValue; item.stateValue = stateValue;
item.drawable = drawable; item.drawable = drawable;
itemAdded(item); itemAdded(item);
} }
private void itemAdded(ref StateItem item) { private void itemAdded(StateItem item) {
_stateList ~= item; _stateList ~= item;
if (!item.drawable.isNull) { if (!item.drawable.isNull) {
if (_size.x < item.drawable.width) if (_size.x < item.drawable.width)
@ -654,22 +671,28 @@ class DrawableCache {
DrawableRef _drawable; DrawableRef _drawable;
DrawableRef[ColorTransform] _transformed; DrawableRef[ColorTransform] _transformed;
//private int _instanceCount; debug(resalloc) private static int _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;
//Log.d("Created DrawableCacheItem, count=", ++_instanceCount); debug(resalloc) Log.d("Created DrawableCacheItem, count=", ++_instanceCount);
} }
~this() { ~this() {
_drawable.clear(); _drawable.clear();
//Log.d("Destroyed DrawableCacheItem, count=", --_instanceCount); foreach(ref t; _transformed)
t.clear();
_transformed.clear();
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() {
if (!_drawable.isNull) if (!_drawable.isNull)
_drawable.clear(); _drawable.clear();
foreach(t; _transformed)
t.clear();
_transformed.clear();
} }
/// mark as not used /// mark as not used
void checkpoint() { void checkpoint() {
@ -864,12 +887,15 @@ class DrawableCache {
debug Log.i("Creating DrawableCache"); debug Log.i("Creating DrawableCache");
} }
~this() { ~this() {
debug Log.i("Destroying DrawableCache"); debug(resalloc) Log.e("Drawable instace count before destroying of DrawableCache: ", ImageDrawable.instanceCount);
Log.i("Destroying DrawableCache _idToDrawableMap.length=", _idToDrawableMap.length);
foreach (ref item; _idToDrawableMap) { foreach (ref item; _idToDrawableMap) {
destroy(item); destroy(item);
item = null; item = null;
} }
_idToDrawableMap.clear(); _idToDrawableMap.clear();
debug(resalloc) Log.e("Drawable instace count after destroying of DrawableCache: ", ImageDrawable.instanceCount);
} }
} }

View File

@ -54,6 +54,8 @@ version(USE_SDL) {
} }
if (_win) if (_win)
SDL_DestroyWindow(_win); SDL_DestroyWindow(_win);
if (_drawbuf)
destroy(_drawbuf);
} }
version(USE_OPENGL) { version(USE_OPENGL) {
@ -828,7 +830,7 @@ version(USE_SDL) {
Platform.setInstance(null); Platform.setInstance(null);
// //
debug { debug(resalloc) {
Widget.shuttingDown(); Widget.shuttingDown();
} }
@ -836,9 +838,18 @@ version(USE_SDL) {
drawableCache = null; drawableCache = null;
imageCache = null; imageCache = null;
FontManager.instance = null; FontManager.instance = null;
debug { debug(resalloc) {
if (DrawBuf.instanceCount > 0) {
Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount);
}
if (Style.instanceCount > 0) {
Log.e("Non-zero Style instance count when exiting: ", Style.instanceCount);
}
if (Widget.instanceCount() > 0) { if (Widget.instanceCount() > 0) {
Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount()); Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount);
}
if (ImageDrawable.instanceCount > 0) {
Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount);
} }
} }
Log.d("Exiting main"); Log.d("Exiting main");

View File

@ -123,6 +123,10 @@ class ImageWidget : Widget {
_drawableId = drawableId; _drawableId = drawableId;
} }
~this() {
_drawable.clear();
}
/// get drawable image id /// get drawable image id
@property string drawableId() { return _drawableId; } @property string drawableId() { return _drawableId; }
/// set drawable image id /// set drawable image id

View File

@ -451,14 +451,18 @@ class Style {
return this; return this;
} }
private static int _instanceCount; debug(resalloc) private static int _instanceCount;
debug(resalloc) @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++;
//Log.d("Created style ", _id, ", count=", ++_instanceCount); //Log.d("Created style ", _id, ", count=", ++_instanceCount);
} }
~this() { ~this() {
foreach(ref Style item; _substates) { foreach(ref Style item; _substates) {
//Log.d("Destroying substate"); //Log.d("Destroying substate");
@ -473,6 +477,7 @@ class Style {
_children.clear(); _children.clear();
_backgroundDrawable.clear(); _backgroundDrawable.clear();
_font.clear(); _font.clear();
debug(resalloc) _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

@ -121,7 +121,7 @@ class Widget {
/// set new trackHover flag value (when true, widget will change Hover state while mouse is moving) /// set new trackHover flag value (when true, widget will change Hover state while mouse is moving)
@property Widget trackHover(bool v) { _trackHover = v; return this; } @property Widget trackHover(bool v) { _trackHover = v; return this; }
debug { debug(resalloc) {
private static int _instanceCount = 0; private static int _instanceCount = 0;
private static bool _appShuttingDown = false; private static bool _appShuttingDown = false;
} }
@ -129,13 +129,12 @@ class Widget {
this(string ID = null) { this(string ID = null) {
_id = ID; _id = ID;
_state = State.Enabled; _state = State.Enabled;
debug { debug(resalloc) _instanceCount++;
_instanceCount++;
}
//Log.d("Created widget, count = ", ++_instanceCount); //Log.d("Created widget, count = ", ++_instanceCount);
} }
~this() { ~this() {
debug { debug(resalloc) {
//Log.v("destroying widget ", _id); //Log.v("destroying widget ", _id);
if (_appShuttingDown) if (_appShuttingDown)
Log.e("Destroying widget ", _id, " after app shutdown: probably, resource leak"); Log.e("Destroying widget ", _id, " after app shutdown: probably, resource leak");
@ -146,7 +145,8 @@ class Widget {
_ownStyle = null; _ownStyle = null;
//Log.d("Destroyed widget, count = ", --_instanceCount); //Log.d("Destroyed widget, count = ", --_instanceCount);
} }
debug {
debug(resalloc) {
/// 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. /// for debug purposes - sets shutdown flag to log widgets not destroyed in time.