I created a simple image viewer in gtkD, which eats up memory every time a new image is displayed. The "same" program in C doesn't show that issue. Looking into src/gdk/Pixbuf.d I can't see the problem immediately.
What am I doing wrong?
C code:
// gcc dvgtk.c $(pkg-config --cflags --libs gtk+-3.0) -o dvgtk
#include <gtk/gtk.h>
static GError *err = NULL;
static GdkPixbuf *pixbuf = NULL;
static GtkWidget *window, *image;
static int filenameidx;
static char const *pfilenames[] = {
"image1.jpg",
"image2.jpg"
};
static gboolean TimeoutFunc(gpointer user_data)
{
char const *pfilename;
pfilename = pfilenames[filenameidx];
if (++filenameidx >= sizeof(pfilenames) / sizeof(pfilenames[0])) filenameidx = 0;
if (pixbuf != NULL) {
g_object_unref(pixbuf);
}
pixbuf = gdk_pixbuf_new_from_file(pfilename, &err);
g_assert_no_error(err);
gtk_image_set_from_pixbuf((GtkImage*)image, pixbuf);
}
int main( int argc, char *argv[])
{
int idx;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 600, 400);
gtk_window_set_title(GTK_WINDOW(window), "Image Test");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
image = gtk_image_new();
gtk_container_add(GTK_CONTAINER(window), image);
g_timeout_add(1000, TimeoutFunc, NULL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
D code:
import core.memory;
import glib.Timeout;
import gdk.Pixbuf;
import gtk.Image;
import gtk.Main;
import gtk.MainWindow;
private class MyMainWindow : MainWindow
{
private int iteration;
private Pixbuf pixbuf;
private Image image;
private size_t filenameIdx;
private string[] filenames = [
"image1.jpg",
"image2.jpg",
];
public this(string text)
{
super(text);
this.setDefaultSize(600, 400);
this.setResizable(false);
this.image = new Image();
this.add(this.image);
new Timeout(1000, &this.cbTimer);
}
private bool cbTimer()
{
auto filename = this.filenames[this.filenameIdx];
if (++this.filenameIdx >= this.filenames.length) this.filenameIdx = 0;
if (this.pixbuf) {
// these lines don't help anything and can be left out
this.pixbuf.destroy();
this.pixbuf = null;
core.memory.GC.collect();
}
this.pixbuf = new Pixbuf(filename);
this.image.setFromPixbuf(this.pixbuf);
// stop after 20 image switches to avoid out of memory
return ++this.iteration < 20;
}
}
void main(string[] args)
{
Main.init(args);
MainWindow win = new MyMainWindow("Image Test");
win.showAll();
Main.run();
}
Of course, the actual program is way bigger.
Replace "image1.jpg"
and "image2.jpg"
with names existing on your system.
Here's some valgrind output. Note that the blocks are meantioned 19 times (which is the switch count of the images):
==00:00:22:00.319 14646== 3,192 (1,520 direct, 1,672 indirect) bytes in 19 blocks are definitely lost in loss record 7,409 of 7,506
==00:00:22:00.319 14646== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==00:00:22:00.319 14646== by 0x5C75610: g_malloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.319 14646== by 0x5C8B22D: g_slice_alloc (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.319 14646== by 0x5C8B76D: g_slice_alloc0 (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x9351DB1: g_type_create_instance (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x9336354: ??? (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x93384C3: g_object_new_valist (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x93388A3: g_object_new (in /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x6A2FD2B: gdk_pixbuf_new_from_data (in /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.3000.7)
==00:00:22:00.320 14646== by 0x6A2DA01: gdk_pixbuf_new (in /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.3000.7)
==00:00:22:00.320 14646== by 0x11BE46E0: ??? (in /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-jpeg.so)
==00:00:22:00.320 14646== by 0x6A31B41: gdk_pixbuf_new_from_file (in /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.3000.7)
==00:00:22:00.320 14646== by 0x6D0492: _D3gdk6Pixbuf6Pixbuf6__ctorMFAyaZC3gdk6Pixbuf6Pixbuf (in dvgtkd)
==00:00:22:00.320 14646== by 0x6B1755: _D6dvgtkd12MyMainWindow7cbTimerMFZb (dvgtkd.d:54)
==00:00:22:00.320 14646== by 0x6F3648: _D4glib7Timeout7Timeout16callAllListenersMFZb (in dvgtkd)
==00:00:22:00.320 14646== by 0x6F35E4: _D4glib7Timeout7Timeout15timeoutCallbackUC4glib7Timeout7TimeoutZb (in dvgtkd)
==00:00:22:00.320 14646== by 0x5C70702: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x5C6FCE4: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x5C70047: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0x5C70309: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.320 14646== by 0xC2E8FE4: gtk_main (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1000.8)
==00:00:22:00.320 14646== by 0x813162: _D3gtk4Main4Main3runFZv (in dvgtkd)
==00:00:22:00.320 14646== by 0x6B17EF: _Dmain (dvgtkd.d:67)
==00:00:22:00.320 14646== by 0x950252: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv (in dvgtkd)
==00:00:22:00.320 14646== by 0x9501A5: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv (in dvgtkd)
==00:00:22:00.320 14646== by 0x95020B: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZv (in dvgtkd)
==00:00:22:00.320 14646== by 0x9501A5: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv (in dvgtkd)
==00:00:22:00.320 14646== by 0x950126: _d_run_main (in dvgtkd)
==00:00:22:00.320 14646== by 0x6BFE9C: main (in dvgtkd)
==00:00:22:00.320 14646==
...
==00:00:22:00.320 14646==
==00:00:22:00.320 14646== 745,524,612 bytes in 19 blocks are possibly lost in loss record 7,506 of 7,506
==00:00:22:00.320 14646== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==00:00:22:00.320 14646== by 0x6A2D9CC: gdk_pixbuf_new (in /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.3000.7)
==00:00:22:00.320 14646== by 0x11BE46E0: ??? (in /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-jpeg.so)
==00:00:22:00.320 14646== by 0x6A31B41: gdk_pixbuf_new_from_file (in /usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0.3000.7)
==00:00:22:00.320 14646== by 0x6D0492: _D3gdk6Pixbuf6Pixbuf6__ctorMFAyaZC3gdk6Pixbuf6Pixbuf (in dvgtkd)
==00:00:22:00.360 14646== by 0x6B1755: _D6dvgtkd12MyMainWindow7cbTimerMFZb (dvgtkd.d:54)
==00:00:22:00.360 14646== by 0x6F3648: _D4glib7Timeout7Timeout16callAllListenersMFZb (in dvgtkd)
==00:00:22:00.360 14646== by 0x6F35E4: _D4glib7Timeout7Timeout15timeoutCallbackUC4glib7Timeout7TimeoutZb (in dvgtkd)
==00:00:22:00.360 14646== by 0x5C70702: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.360 14646== by 0x5C6FCE4: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.360 14646== by 0x5C70047: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.360 14646== by 0x5C70309: g_main_loop_run (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0)
==00:00:22:00.360 14646== by 0xC2E8FE4: gtk_main (in /usr/lib/x86_64-linux-gnu/libgtk-3.so.0.1000.8)
==00:00:22:00.360 14646== by 0x813162: _D3gtk4Main4Main3runFZv (in dvgtkd)
==00:00:22:00.360 14646== by 0x6B17EF: _Dmain (dvgtkd.d:67)
==00:00:22:00.360 14646== by 0x950252: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv (in dvgtkd)
==00:00:22:00.360 14646== by 0x9501A5: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv (in dvgtkd)
==00:00:22:00.360 14646== by 0x95020B: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZv (in dvgtkd)
==00:00:22:00.360 14646== by 0x9501A5: _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv (in dvgtkd)
==00:00:22:00.360 14646== by 0x950126: _d_run_main (in dvgtkd)
==00:00:22:00.360 14646== by 0x6BFE9C: main (in dvgtkd)
I'm using GtkD-2.4.0, but had the same problem with GtkD-2.3.1.
Thanks for your help,
Diez
PS: Got
500 - Internal Server Error
Internal Server Error
Internal error information:
object.Exception@../../../root/.dub/packages/vibe-d-0.7.19/source/vibe/utils/dictionarylist.d(134): Accessing non-existent key 'confirmemail'.
vibenews(pure @safe bool std.exception.enforce!(bool).enforce(bool, lazy const(char)[], immutable(char)[], uint)+0x22) [0x846ded2]
vibenews(const(pure @safe immutable(char)[] function(immutable(char)[])) vibe.utils.dictionarylist.DictionaryList!(immutable(char)[], true).DictionaryList.opIndex+0x6c) [0x83e0344]
vibenews(void vibenews.web.WebInterface.postArticle(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse)+0x1fc) [0x830692c]
vibenews(void vibe.http.router.URLRouter.handleRequest(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse)+0xff) [0x83cd837]
vibenews(bool vibe.http.server.handleRequest(vibe.core.stream.Stream, vibe.core.net.TCPConnection, vibe.http.server.HTTPServerListener, ref vibe.http.server.HTTPServerSettings, ref bool)+0xf74) [0x83d1f2c]
vibenews(void vibe.http.server.handleHTTPConnection(vibe.core.net.TCPConnection, vibe.http.server.HTTPServerListener)+0xc7) [0x83d0f07]
vibenews(void vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse)).doListen(vibe.http.server.HTTPServerSettings, vibe.http.server.HTTPServerListener, immutable(char)[]).lambda4(vibe.core.net.TCPConnection)+0x1f) [0x83ce2f7]<br>vibenews(void vibe.core.drivers.libevent2_tcp.onConnect(int, short, void*).ClientTask.execute()+0x221) [0x837e081]<br>vibenews(_D4vibe4core4core12T7runTaskZ7runTaskFDFZvZS4vibe4core4task4Task12callDelegateFC4vibe4core4core8CoreTaskZv+0x1f) [0x836ff17]
vibenews(void vibe.core.core.CoreTask.run()+0xca) [0x836d252]
vibenews(void core.thread.Fiber.run()+0x21) [0x8482171]
vibenews(fiber_entryPoint+0x49) [0x84820a9]
[(nil)]