View previous topic :: View next topic |
Author |
Message |
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Wed Mar 26, 2008 7:46 pm Post subject: Memory bug in gtkD? |
|
|
Hey guys.
I think I may have found a bug in gtkD, but I'm not 100% sure if its not actually my fault.
I wrote an application with gtkD with glade. The main() function is not much more than this:
Code: | glXml = new Glade(gladeFile);
new FrontWnd;
GtkD.main(); |
The FrontWnd hooks up all the handlers and etc when it is created.
It all normally runs fine, but I was worrying to myself about if the garbage collector might actually clean up 'FrontWnd' since technically there are no solid references to it. So, as a simple test I added "std.gc.fullCollect();" after "new FrontWnd" is called. The program still runs fine, and FrontWnd's destructor is never called so it all seems ok. But then I click on a combobox and the program segfaults. I've traced the error down to a line:
Code: |
private void onChangeMenu(ComboBox cb){
TreeModel model = cb.getModel(); //Here.
...
|
it seems calling getModel on the passed param causes the segmentation fault, but this only happens if I run a fullCollect before calling GtkD.main();
Perhaps something in gtkD is getting cleaned up when it shouldn't? I've also noticed that after fiddling with the interface for a few seconds, all of the event callbacks just stop working. They never get called when they should.
Is this my doing, or a problem in gtkD? |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Thu Mar 27, 2008 4:35 pm Post subject: |
|
|
Normally the pointers to the gtk structs get added as a root to the garbage collector.
How does FrontWnd hook up the handlers? |
|
Back to top |
|
|
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Thu Mar 27, 2008 9:37 pm Post subject: |
|
|
Mike Wey wrote: | Normally the pointers to the gtk structs get added as a root to the garbage collector.
How does FrontWnd hook up the handlers? |
Code: | (cast(ComboBox)glXml.getWidget("Menu")).addOnChanged(&onChangeMenu); |
Perhaps I need to store the widgets I get from the glade object? |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Sat Mar 29, 2008 6:34 am Post subject: |
|
|
The GtkD class instance is added as a pionter to the data when connecting the signals. I don't know where gtk stores this data, it might be someware the Garbage Collector can't find it. whitch leeds to it collecting the GtkD classes.
Storing the Widgets should stop the Garbage Collector from collecting them. |
|
Back to top |
|
|
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Sat Mar 29, 2008 7:54 pm Post subject: |
|
|
Mike Wey wrote: | The GtkD class instance is added as a pionter to the data when connecting the signals. I don't know where gtk stores this data, it might be someware the Garbage Collector can't find it. whitch leeds to it collecting the GtkD classes.
Storing the Widgets should stop the Garbage Collector from collecting them. |
Hmm, this should probably be handled by the glade object. You shouldn't need to store glade pointers, they're usually just called then thrown away again.
Oh well, for now I'll just keep an associative array of widgets and it should hopefully fix the problem.
EDIT: It did fix it. |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Sun Mar 30, 2008 8:27 am Post subject: |
|
|
Quote: | Normally the pointers to the gtk structs get added as a root to the garbage collector. |
Did some more searching and actually a pointer to the GtkD class gets added as a root for the garbage collector and the pointer is stored in the associated gtk struct. So the Garbage Collector shouldn't collect the GtkD classes. |
|
Back to top |
|
|
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Mon Mar 31, 2008 6:51 pm Post subject: |
|
|
Mike Wey wrote: | Quote: | Normally the pointers to the gtk structs get added as a root to the garbage collector. |
Did some more searching and actually a pointer to the GtkD class gets added as a root for the garbage collector and the pointer is stored in the associated gtk struct. So the Garbage Collector shouldn't collect the GtkD classes. |
So, why are the objects being collected? Is there some kind of explicit delete going on? Or perhaps addroot isn't being used properly? |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Tue Apr 01, 2008 3:36 pm Post subject: |
|
|
I can't think of any explicit deleting someware, i also haven't been able to reproduce this. I tried hooking up 50 buttons in the same way FrontWnd does it and calling fullCollect before GtkD.Main(). hasn't led to any problems yet.
Might i ask wicht versions of the compiler and phobos/tango you are using? |
|
Back to top |
|
|
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Wed Apr 02, 2008 5:45 am Post subject: |
|
|
I'm using DMD 1.028, and the latest phobos v1 that comes with it.
I also have the latest preview release of gtkD.
Are you using a glade file to try and reproduce these results? |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Wed Apr 02, 2008 12:27 pm Post subject: |
|
|
Yes i am using glade, and i'm changing the text on the buttons to see if the reference that gets passed to function is still valid. |
|
Back to top |
|
|
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Thu Apr 03, 2008 3:51 am Post subject: |
|
|
I've been looking into it a bit more.
Oddly enough buttons work. As far as I can see, only combo boxes are having this problem. I checked to see if it was calling 'getModel' that caused the error but it appears that calling anything on the combobox object causes a segfault.
Maybe there is something wrong with the way comboboxes register events? specifically, addOnChanged? |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Fri Apr 04, 2008 2:04 pm Post subject: |
|
|
I haven't had any luck reproducing this with comboboxes. |
|
Back to top |
|
|
okibi
Joined: 04 Jan 2007 Posts: 170
|
Posted: Sat Apr 05, 2008 7:21 am Post subject: |
|
|
I couldn't reproduce this with comboboxes either.
However, if I create an associative array of textbuffers (such as TextBuffer[char[]]) and connect the addOnChanged function to an outside function to handle it, I can get a segfault every now and then.
I'll continue to look into this issue. |
|
Back to top |
|
|
TiMBuS
Joined: 21 Dec 2007 Posts: 11
|
Posted: Mon Apr 14, 2008 5:02 am Post subject: |
|
|
Okay I've been away a bit and focusing on some Perl work so I haven't really looked further into this.
So just a few minutes ago I thought I should have a more in-depth look and maybe post a simple example to recreate the error (which I may still do). So, I was stripping down the program so I could post a quick example, when I noticed this in the constructor of FrontWnd:
Code: | (cast(ComboBox)glXml.getWidget("Menu")).addOnChanged(&onChangeMenu);
//Other stuff...
ComboBox cb = cast(ComboBox)glXml.getWidget("Menu");
fillComboBox(cb, ["foo","bar","baz"]);
cb.setActive(0); |
For some reason it seemed significant, so I changed it into this:
Code: | //(cast(ComboBox)glXml.getWidget("Menu")).addOnChanged(&onChangeMenu);
//Other stuff...
ComboBox cb = cast(ComboBox)glXml.getWidget("Menu");
cb.addOnChanged(&onChangeMenu);
fillComboBox(cb, ["foo","bar","baz"]);
cb.setActive(0); |
No segfault.
I also just tried this:
Code: | (cast(ComboBox)glXml.getWidget("Menu")).addOnChanged(&onChangeMenu);
//Other stuff...
ComboBox cb = cast(ComboBox)glXml.getWidget("Menu");
cb.addOnPopup(&doNothing);
fillComboBox(cb, ["foo","bar","baz"]);
cb.setActive(0); |
doNothing() just writes the passed combobox's 'getActive' function to the console. doNothing works without error, but changing the menu option gives a segfault.
Reversing the positions of addOnChanged and addOnPopup makes changing the menu option work, but triggering the popup gives a segfault.
So I guess it's something to do with creating two references to the same glade object in the same scope? It somehow makes the first reference invalid? |
|
Back to top |
|
|
Mike Wey
Joined: 07 May 2007 Posts: 428
|
Posted: Wed Apr 16, 2008 2:28 pm Post subject: |
|
|
I was working on this a bit more today, and i'm now able to reproduce the segfault this time. The first time i was doing something along the lines of the second example you posted.
Here is the code i used this time:
Code: | module glade.textGlade;
import glade.Glade;
import gtk.GtkD;
import gtk.Window;
import gtk.Widget;
import gtk.ComboBox;
import gtk.TreeIter;
import gtk.ListStore;
import gtk.CellRenderer;
import gtk.CellRendererText;
version(Tango){
import tango.stdc.stdlib : exit;
import tango.io.Stdout;
import tango.text.Util;
import tango.core.Memory;
void writefln( string frm, ... ){
string frm2 = substitute( frm, "%s", "{}" );
Stdout( Stdout.layout.convert( _arguments, _argptr, frm2 )).newline;
}
}
else{
import std.stdio;
import std.c.process;
import std.gc;
}
class Test
{
this()
{
Glade g = new Glade("gladeTest.glade");
(cast(Window)g.getWidget("window1")).setTitle("This is a glade window");
(cast(ComboBox)g.getWidget("combobox1")).addOnChanged( &test );
ListStore listStore = new ListStore([GType.STRING]);
TreeIter iterTop = listStore.createIter();
listStore.setValue(iterTop,0,"Test");
listStore.append(iterTop);
listStore.setValue(iterTop,0,"Test");
(cast(ComboBox)g.getWidget("combobox1")).setModel(listStore);
(cast(ComboBox)g.getWidget("combobox1")).setWrapWidth(1);
CellRenderer renderer = new CellRendererText();
(cast(ComboBox)g.getWidget("combobox1")).packStart(renderer, true);
(cast(ComboBox)g.getWidget("combobox1")).addAttribute(renderer, "text",0);
(cast(Window)g.getWidget("window1")).addOnHide( delegate void(Widget aux){ exit(0); } );
(cast(Window)g.getWidget("window1")).showAll();
}
void test(ComboBox cbx)
{
auto model = cbx.getModel();
}
}
int main(string[] args)
{
GtkD.init(args);
new Test;
version(Tango)
GC.collect();
else
fullCollect();
GtkD.main();
return 0;
} |
|
|
Back to top |
|
|
|