Re: Fwd: Problem with memory management with builder.



Hi Krzysztof,

I expanded your program a bit (see attachment) and made some tests.

When UNDO_REF_FROM_GET_WIDGET is *not* defined, the program ends
normally, and its output is:
1 button->ref_count=3
1 treeview->ref_count=3
2 window->ref_count=3
2 button->ref_count=3
2 treeview->ref_count=3
4 button->ref_count=2
4 treeview->ref_count=2
5 button->ref_count=1
5 treeview->ref_count=1
valgrind does not report any reading or writing in freed memory.
Contrary to your results, neither "delete button" nor "delete treeview"
causes segmentation fault or any other problem.

When UNDO_REF_FROM_GET_WIDGET *is* defined, the ref counts that were
increased by get_widget() are decreased after those calls. Then the
program behaves very differently. The output is
1 button->ref_count=3
1 treeview->ref_count=3
2 window->ref_count=3
2 button->ref_count=3
2 treeview->ref_count=3
3 button->ref_count=2
3 treeview->ref_count=2
4 button->ref_count=1
4 treeview->ref_count=1
and then a segmentation fault at line 51, std::cout << "5
button->ref_count=".....

valgrind reports accesses to freed memory, e.g.
Invalid read of size 4
  at 0x8049BBD: Gtk::Button::gobj() (button.h:98)
  by 0x804973D: main (main.cc:51)
Address 0x56cafa8 is 0 bytes inside a block of size 40 free'd
  at 0x4025907: operator delete(void*) (vg_replace_malloc.c:387)
  by 0x41CD939: Gtk::Button::~Button() (button.cc:428)
......
  by 0x45C570F: gtk_builder_finalize (gtkbuilder.c:350)

I interpret this as if the button is deleted when the Gtk::Builder is
deleted. But if "delete window;" is removed, the button is deleted by
"delete button;".

To summarize:
A child widget that has not been fetched with Gtk::Builder::get_widget()
is deleted when its container and the Gtk::Builder object have both been
deleted.

A child widget that has been fetched with Gtk::Builder::get_widget() is
deleted only explicitly (e.g. by delete button).
(Glib::ObjectBase::unreference() is not recommended. It shall only be
used internally in glibmm, gtkmm, and similar C++ binding modules.)

A widget which is not the child of a window or other container, is
deleted only explicitly.


What are aiming at with your questions? Are you just curious, or do you
want to know what you need to do to avoid memory leaks? Or perhaps both?

I suppose that usually you create a Gtk::Builder at the start of the
program. Then that Builder exists until the program ends. While the
program is running, you call Gtk::Builder::get_widget() now and then. I
don't think you need to worry much about memory leaks in such a case. If
you call get_widget() to get the same widget several times, you will get
a pointer to the same object each time. If there is allocated memory
when the program ends, it doesn't matter. The operating system will take
back all memory that the program has used.

Obviously the author of the gtkmm tutorial does not agree with me.
Curiously, in the example program that follows the paragraph that you
quote, pDialog is not deleted.

/Kjell

tis 2011-06-21 klockan 01:31 +0200 skrev Krzysztof Łochwinowicz:

> 
> 
> Hi, in documentation (i.e official gtkmm tutorial) I have found this:
> 
> 
> get_widget() returns child widgets that are manage()ed (see the Memory
> Management chapter), so they will be deleted when their parent
> container is deleted. So, if you get only a child widget
> from Gtk::Builder, instead of a whole window, then you must either put
> it in a Container or delete it. Windows (such asDialogs) cannot be
> managed because they have no parent container, so you must delete them
> at some point. 
> 
> 
> But I do not fully understand it. In first part it tells that widget
> dies with window. So when I retrieve a window and delete it, it will
> delete widgets.. but when I retrieve window and widget, the widget
> will not be deleted. Am I right? So why treeview is deleted after
> deleting the window and button is not? I get pointer to treeview the
> same way I get pointer to button.

> -----------------------------------------------------------
> Krzysztof Łochwinowicz
> 

#include <gtkmm.h>
#include <iostream>

//#define UNDO_REF_FROM_GET_WIDGET 1

int main(int argc, char** argv)
{
   Gtk::Main kit(argc, argv);
   Gtk::Button* button;
   Gtk::TreeView* treeview;
   {
      Gtk::Window* window;
      Glib::RefPtr<Gtk::Builder> refBuilder = Gtk::Builder::create();
      try
      {
         refBuilder->add_from_file("ssshm.ui"); // with window and button
      }
      catch (const Glib::FileError& ex)
      {
         std::cerr << "FileError: " << ex.what() << std::endl;
         return 1;
      }
      catch (const Gtk::BuilderError& ex)
      {
         std::cerr << "BuilderError: " << ex.what() << std::endl;
         return 1;
      }
      refBuilder->get_widget("button_load", button);
      refBuilder->get_widget("treeview_hosts", treeview);
      std::cout << "1 button->ref_count=" << G_OBJECT(button->gobj())->ref_count << std::endl;
      std::cout << "1 treeview->ref_count=" << G_OBJECT(treeview->gobj())->ref_count << std::endl;
      refBuilder->get_widget("window1", window);
      std::cout << "2 window->ref_count=" << G_OBJECT(window->gobj())->ref_count << std::endl;
      std::cout << "2 button->ref_count=" << G_OBJECT(button->gobj())->ref_count << std::endl;
      std::cout << "2 treeview->ref_count=" << G_OBJECT(treeview->gobj())->ref_count << std::endl;
      window->show_all();
#ifdef UNDO_REF_FROM_GET_WIDGET
      // Undo the reference set by 
      // refBuilder->get_widget("button_load", button);
      // refBuilder->get_widget("treeview_hosts", treeview);
      button->unreference();
      treeview->unreference();
      std::cout << "3 button->ref_count=" << G_OBJECT(button->gobj())->ref_count << std::endl;
      std::cout << "3 treeview->ref_count=" << G_OBJECT(treeview->gobj())->ref_count << std::endl;
#endif
      kit.run(*window);
      delete window;
      std::cout << "4 button->ref_count=" << G_OBJECT(button->gobj())->ref_count << std::endl;
      std::cout << "4 treeview->ref_count=" << G_OBJECT(treeview->gobj())->ref_count << std::endl;
   } // builder dies here..
   std::cout << "5 button->ref_count=" << G_OBJECT(button->gobj())->ref_count << std::endl;
   std::cout << "5 treeview->ref_count=" << G_OBJECT(treeview->gobj())->ref_count << std::endl;
   delete button;  // Program exits normally, no double delete.
   delete treeview;
}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]