GObject memory statistics



Ben Maurer has recently asked where the heap 
goes that GTK+ apps use. Here is a very quick
patch to add some statistics to GObject. 
Applying this to a e.g. gtk-demo yields 
something like

[...]
49 GdkWindow, 4312 bytes
49 GdkWindowImplX11, 4900 bytes
117 GParamInt, 6084 bytes
190 GParamBoolean, 8360 bytes
13 GtkStyle, 9828 bytes
35 GtkRcStyle, 11620 bytes
53 PangoCairoFcFont, 12084 bytes
total: 106020 bytes

So, in terms of memory used by objects, 
PangoCairoFcFont and GtkRcStyle are the
main offenders in this example.

Matthias


Index: gobject/gtype.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gtype.c,v
retrieving revision 1.88
diff -u -r1.88 gtype.c
--- gobject/gtype.c	15 Jun 2006 19:18:51 -0000	1.88
+++ gobject/gtype.c	4 Jul 2006 07:30:15 -0000
@@ -1518,6 +1518,90 @@
   return node ? node->class : NULL;
 }
 
+/* quick hack to collect some memory statistics */
+
+#include <signal.h>
+
+static GHashTable *type_stats = NULL;
+
+typedef struct 
+{
+  GType type;
+  gint count;
+  gint size;
+} TypeStat;
+
+static void
+dump_stat (gpointer value, gpointer data)
+{
+  TypeStat *ts = (TypeStat*)value;
+  gint *total = (gint *)data;
+
+  g_print ("%d %s, %d bytes\n", ts->count, g_type_name (ts->type), ts->size);
+  *total += ts->size;
+}
+
+static gint
+compare_type_stats (gconstpointer a, gconstpointer b)
+{
+  TypeStat *as = (TypeStat *)a;
+  TypeStat *bs = (TypeStat *)b;
+
+  return as->size - bs->size;
+}
+
+static void
+collect_stats (gpointer key, gpointer value, gpointer data)
+{
+  GList **list = (GList **)data;
+
+  *list = g_list_insert_sorted (*list, value, compare_type_stats);
+}
+
+static void
+dump_type_stats (void)
+{
+  GList *stats = NULL;
+  gint total = 0;
+
+  g_hash_table_foreach (type_stats, collect_stats, &stats);
+  g_list_foreach (stats, dump_stat, &total); 
+  g_print ("total: %d bytes\n", total); 
+  g_list_free (stats);
+}
+
+static void
+change_instance_count (GType type, gint delta)
+{
+  TypeStat *data;
+  TypeNode *node;
+
+  node = lookup_type_node_I (type);
+  if (!type_stats)
+    {
+      g_print ("starting type statistics\n");
+      g_atexit (dump_type_stats);
+      signal (SIGUSR1, dump_type_stats);
+
+      type_stats = g_hash_table_new (g_direct_hash, g_direct_equal);
+    }
+
+  data = (TypeStat*) g_hash_table_lookup (type_stats, GINT_TO_POINTER (type));
+ 
+  if (!data)
+    {
+      data = g_new0 (TypeStat, 1);
+      data->type = type;
+      data->count = 0;
+      data->size = 0;
+    } 
+
+  data->count += delta;
+  data->size += delta * type_total_instance_size_I (node);
+
+  g_hash_table_replace (type_stats, GINT_TO_POINTER (type), data); 
+}
+
 GTypeInstance*
 g_type_create_instance (GType type)
 {
@@ -1544,6 +1628,8 @@
   class = g_type_class_ref (type);
   total_size = type_total_instance_size_I (node);
 
+  change_instance_count (type, +1);
+
   instance = g_slice_alloc0 (total_size);
 
   if (node->data->instance.private_size)
@@ -1593,6 +1679,8 @@
       return;
     }
   
+  change_instance_count (class->g_type, -1);
+
   instance->g_class = NULL;
 #ifdef G_ENABLE_DEBUG  
   memset (instance, 0xaa, type_total_instance_size_I (node));


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