About the glib's memory management



I have a question about the glib memory management about the cycle reference.
The model is a Pet class. One pet maybe have a friend. Its friend is a Pet, too.
There is a kind of condition like this:
Pet A has a friend Pet B, Pet B has a friend Pet A too.
It means that Pet A holds a Pet B's reference and Pet B holds a Pet A's reference too.
When I only g_object_unref(PetA) or g_object_unref(PetB), the dispose method for PetA and PetB will never be invoked.
That means they will not be free forever.
One solution is that I must detect the cycle myself and run at last dispose method at least once.
But it seems it's not reliable because not all cycles will be detected by the developers.  Is there any better method to solve
the problem?
The following is my codes:

#pet.h
#ifndef PET_H
#define PET_H


/**
 *Type macros
 */
typedef struct _Pet Pet;
typedef struct _PetClass PetClass;

/**
 *Type macros for private structure 
 */
typedef struct _PrivStruct PrivStruct;

struct _Pet{
  GObject parent;
  
  /*instance members*/
  /*private*/
  PrivStruct *priv;
};

struct _PetClass {
  GObjectClass parent;
};

/*Get type method*/

static GType pet_get_type(void);

static gint pet_get_ages(Pet *pet);

static void pet_set_ages(Pet *pet,int ages);

static const gchar* pet_get_name(Pet *pet);

static void pet_set_name(Pet *pet,const char *name);

static Pet* pet_get_friend(Pet *pet);

static void pet_set_friend(Pet *pet,Pet *friend);


/*define helper macros*/

#define TYPE_PET             (pet_get_type())
#define PET(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),TYPE_PET,PetClass))
#define PET_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST((klass),TYPE_PET,PetClass))
#define IS_PET(obj)          (G_TYPE_CHECK_INSTANCE_TYPE((obj),TYPE_PET))
#define IS_PET_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE((klass),TYPE_PET))
#define PET_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj),TYPE_PET,PetClass))
#endif


#pet.c
#include <glib-object.h>
#include "pet.h"
 
static GObjectClass *parent;

struct _PrivStruct{
  gboolean isDispose;
  gint ages;
  const gchar *name;
  Pet *friend;
};

static Pet* pet_get_friend(Pet *pet){
  if(pet){
    return pet->priv->friend;
  }else{
    return NULL;
  }
}

static void pet_set_friend(Pet *pet,Pet *friend){
  if(pet){ 
    if(pet->priv->friend)
      g_object_unref(pet->priv->friend);
    g_object_ref(friend);
    pet->priv->friend = friend;
  }
}

static void pet_dispose(GObject *object){
  Pet *self = (Pet*)object;
  g_print("run dispose address is %x \r\n",self);
  if(self->priv->isDispose){
    return ;
  }
  g_print("dispose name is %s\r\n",pet_get_name(self));
     
  g_object_unref(self->priv->friend);
  self->priv->isDispose = TRUE;
  parent->dispose(object);
}

static const gchar* pet_get_name(Pet *pet){
  if(pet){
    return pet->priv->name;
  }else{
    return NULL;
  }
}

static void pet_set_name(Pet *pet,const char *name){
  if(pet){
    pet->priv->name = name;
  }
}

static gint pet_get_ages(Pet *pet){
  if((pet)&&(pet->priv)){
    return pet->priv->ages;
  }
  return 0;
}

static void pet_set_ages(Pet *pet,int ages){
  if(pet){
    g_print("set ages, the address is %x",pet);
    if(!(pet->priv)){
      pet->priv = g_newa(PrivStruct,1);
    }
    pet->priv->ages = ages;
  }
}



static void pet_finalize(GObject *object) {
  g_print("finalize...");
  Pet *self = (Pet*)object;
  g_free(self->priv);
  parent->finalize(object);
}

static GObject *pet_constructor(GType type,
				guint n_construct_properties,
				GObjectConstructParam *construct_properties){
  g_print("hello constructor \r\n");
  GObject *obj;
  {
    obj = parent->constructor(type,
			      n_construct_properties,
			      construct_properties);
  }

  Pet *self = (Pet *)obj;
  self->priv = g_new0(PrivStruct,1);
  self->priv->isDispose = FALSE;
  return obj;
}


static void pet_class_init(gpointer g_class,
		     gpointer g_class_data){
  g_print("init class \n");
  PetClass *klass = PET_CLASS(g_class);  
  parent = G_OBJECT_CLASS(g_type_class_peek_parent(klass));
  ((GObjectClass*)klass)->constructor = pet_constructor;
  ((GObjectClass*)klass)->finalize = pet_finalize;
  ((GObjectClass*)klass)->dispose = pet_dispose;
}

static void pet_instance_init(GTypeInstance *instance,
			      gpointer      g_class){
  g_print("hello init\r\n");
}

static GType pet_get_type(){
  static GType type = 0;
  if(type == 0){
    g_print("regist pet type\r\n");
    static const GTypeInfo info = {
      sizeof(PetClass),
      NULL,/*base_init*/
      NULL,/*base_finalize*/
      pet_class_init,/*class_init*/
      NULL,/*class_finalize*/
      NULL,
      sizeof(Pet),
      0,/*n_preallocs*/
      pet_instance_init         /*instance_init*/
    };
    type = g_type_register_static(G_TYPE_OBJECT,
				  "LinyyPetType",
				  &info,0);
    g_print("the type id is %d\r\n",type);
    
  }
  return type;
}



int main(int argc,char *argv[]) {
  g_print("hello\r\n");
  g_type_init();
  
  Pet *petGougou = g_object_new(TYPE_PET,NULL);
  pet_set_name(petGougou,"gougou");
  int age = pet_get_ages(petGougou);
  g_print("it's age is %d\r\n",age);
  g_print("it's name is %s\r\n",pet_get_name(petGougou));
  g_print("now the name is %s\r\n",pet_get_name(petGougou));
  Pet *petXiaomi ;
  petXiaomi = g_object_new(TYPE_PET,NULL);
  pet_set_name(petXiaomi,"xiaomi");
  //set friend
  pet_set_friend(petGougou,petXiaomi);
  pet_set_friend(petXiaomi,petGougou);
  g_print("Gougou's friend is %s\r\n",pet_get_name(pet_get_friend(petGougou)));
  g_print("Xiaomi's friend is %s\r\n",pet_get_name(pet_get_friend(petXiaomi)));
  g_print("begin to finalize\r\n");
  ((GObjectClass *)PET_GET_CLASS(petXiaomi))->dispose(G_OBJECT(petXiaomi));
  
  g_object_unref(petGougou);  
  g_object_unref(petXiaomi);
  return 0;
}





-- 
Best regards,
Yueyu Lin
-------




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