Again, it is often difficult to figure out which mechanism to use to hook into the object's destruction process: when the last g_object_unref function call is made, a lot of things happen as described in Table 2, “g_object_unref”.

The destruction process of your object must be split is two different phases: you must override both the dispose and the finalize class methods.

struct _MamanBarPrivate {
  gboolean dispose_has_run;
};

static GObjectClass parent_class = NULL;

static void
bar_dispose (GObject *obj)
{
  MamanBar *self = (MamanBar *)obj;

  if (self->private->dispose_has_run) {
   /* If dispose did already run, return. */
    return;
  }
  /* Make sure dispose does not run twice. */
  object->private->dispose_has_run = TRUE;

  /* 
   * In dispose, you are supposed to free all types referenced from this
   * object which might themselves hold a reference to self. Generally,
   * the most simple solution is to unref all members on which you own a 
   * reference.
   */

   /* Chain up to the parent class */
   G_OBJECT_CLASS (parent_class)->dispose (obj);
}

static void
bar_finalize (GObject *obj)
{
  MamanBar *self = (MamanBar *)obj;

  /*
   * Here, complete object destruction.
   * You might not need to do much...
   */
  g_free (self->private);

   /* Chain up to the parent class */
   G_OBJECT_CLASS (parent_class)->finalize (obj);
}

static void
bar_class_init (BarClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->dispose = bar_dispose;
  gobject_class->finalize = bar_finalize;
}

static void
maman_bar_init (GTypeInstance   *instance,
                gpointer         g_class)
{
  MamanBar *self = (MamanBar *)instance;
  self->private = g_new0 (MamanBarPrivate, 1);
  self->private->dispose_has_run = FALSE;

  parent_class = g_type_class_peek_parent (klass);
}

Add similar code to your GObject, make sure the code still builds and runs: dispose and finalize must be called during the last unref. It is possible that object methods might be invoked after dispose is run and before finalize runs. GObject does not consider this to be a program error: you must gracefully detect this and neither crash nor warn the user. To do this, you need something like the following code at the start of each object method, to make sure the object's data is still valid before manipulating it:

if (self->private->dispose_has_run) {
  /* Dispose has run. Data is not valid anymore. */
  return;
}