diff --git a/glib/gdataset.c b/glib/gdataset.c
index 86970c9..082c180 100644
--- a/glib/gdataset.c
+++ b/glib/gdataset.c
@@ -930,6 +930,30 @@ g_datalist_get_flags (GData **datalist)
   return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
 }
 
+/* called on shutdown, must free all allocated data */
+static void
+g_data_at_shutdown (gpointer user_data)
+{
+  if (g_dataset_location_ht != NULL)
+    {
+      /* TODO: free elements */
+      g_hash_table_destroy (g_dataset_location_ht);
+      g_dataset_location_ht = NULL;
+    }
+  if (g_dataset_cached != NULL)
+    {
+      /* TODO */
+      g_assert_not_reached ();
+    }
+
+  if (g_quark_ht != NULL)
+    {
+      g_hash_table_destroy (g_quark_ht);
+    }
+  g_free (g_quarks);
+  g_quarks = NULL;
+}
+
 /* HOLDS: g_dataset_global_lock */
 static void
 g_data_initialize (void)
@@ -938,6 +962,8 @@ g_data_initialize (void)
 
   g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
   g_dataset_cached = NULL;
+
+  g_mem_notify_at_shutdown (NULL, g_data_at_shutdown);
 }
 
 /**
@@ -1015,12 +1041,15 @@ quark_strdup(const gchar *string)
   gchar *copy;
   gsize len;
 
+  if (!g_dataset_location_ht)
+    g_data_initialize ();
+
   len = strlen (string) + 1;
 
   /* For strings longer than half the block size, fall back
      to strdup so that we fill our blocks at least 50%. */
   if (len > QUARK_STRING_BLOCK_SIZE / 2)
-    return g_strdup (string);
+    return g_mem_free_at_shutdown (g_strdup (string));
 
   if (quark_block == NULL ||
       QUARK_STRING_BLOCK_SIZE - quark_block_offset < len)
@@ -1139,7 +1168,10 @@ static inline GQuark
 g_quark_new (gchar *string)
 {
   GQuark quark;
-  
+
+  if (!g_dataset_location_ht)
+    g_data_initialize ();
+
   if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
     g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
   if (!g_quark_ht)
diff --git a/glib/gmem.c b/glib/gmem.c
index 2c9b74a..bbc8b85 100644
--- a/glib/gmem.c
+++ b/glib/gmem.c
@@ -40,6 +40,7 @@
 #include "gtestutils.h"
 #include "gthread.h"
 #include "glib_trace.h"
+#include "garray.h"
 
 
 #define MEM_PROFILE_TABLE_SIZE 4096
@@ -404,6 +405,8 @@ g_mem_set_vtable (GMemVTable *vtable)
 }
 
 
+static void g_mem_shutdown_init (void);
+
 /* --- memory profiling and checking --- */
 #ifdef	G_DISABLE_CHECKS
 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
@@ -1195,4 +1198,101 @@ _g_mem_thread_init_noprivate_nomessage (void)
 #ifndef G_DISABLE_CHECKS
   gmem_profile_mutex = g_mutex_new ();
 #endif
+  g_mem_shutdown_init ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+  gpointer user_data;
+  GDestroyNotify callback;
+} ShutdownNotifier;
+
+static GMutex *gmem_shutdown_mutex = NULL;
+static GArray *shutdown_notifiers = NULL;
+
+
+static void
+g_mem_shutdown_init (void)
+{
+  gmem_shutdown_mutex = g_mutex_new ();
+  if (shutdown_notifiers == NULL)
+    shutdown_notifiers = g_array_new (FALSE, FALSE, sizeof (ShutdownNotifier));
+}
+
+void
+g_mem_shutdown (void)
+{
+  gint n;
+
+  /* run all notifiers/frees in reverse order */
+  for (n = shutdown_notifiers->len - 1; n >= 0; n--)
+    {
+      ShutdownNotifier *notifier;
+      notifier = &g_array_index (shutdown_notifiers, ShutdownNotifier, n);
+      notifier->callback (notifier->user_data);
+    }
+  g_array_unref (shutdown_notifiers);
+}
+
+gpointer
+g_mem_free_at_shutdown (gpointer mem)
+{
+  /* could maybe not waste memory here */
+  return g_mem_notify_at_shutdown (mem, g_free);
+}
+
+gpointer
+g_mem_slice_free_at_shutdown (gsize     block_size,
+                              gpointer  mem_block)
+{
+  /* TODO: implement */
+  g_assert_not_reached ();
+  return mem_block;
+}
+
+gpointer
+g_mem_notify_at_shutdown (gpointer        user_data,
+                          GDestroyNotify  callback)
+{
+  ShutdownNotifier notifier;
+
+  g_mutex_lock (gmem_shutdown_mutex);
+  notifier.user_data = user_data;
+  notifier.callback = callback;
+  /* this can happen when called before g_mem_shutdown_init() is called e.g. before
+   * GMutex is available
+   */
+  if (shutdown_notifiers == NULL)
+    shutdown_notifiers = g_array_new (FALSE, FALSE, sizeof (ShutdownNotifier));
+  g_array_append_val (shutdown_notifiers, notifier);
+  g_mutex_unlock (gmem_shutdown_mutex);
+
+  return user_data;
+}
+
+void
+g_mem_remove_notify_at_shutdown (gpointer           user_data,
+                                 GDestroyNotify     callback)
+{
+  guint n;
+
+  g_mutex_lock (gmem_shutdown_mutex);
+  for (n = 0; n < shutdown_notifiers->len; n++)
+    {
+      ShutdownNotifier *notifier;
+      notifier = &g_array_index (shutdown_notifiers, ShutdownNotifier, n);
+      if (notifier->user_data == user_data &&
+          notifier->callback == callback)
+        {
+          g_array_remove_index (shutdown_notifiers, n);
+          goto out;
+        }
+    }
+
+  g_warning (G_STRLOC ": didn't find notifier to remove");
+
+ out:
+  g_mutex_unlock (gmem_shutdown_mutex);
 }
diff --git a/glib/gmem.h b/glib/gmem.h
index d005eb1..57594c8 100644
--- a/glib/gmem.h
+++ b/glib/gmem.h
@@ -198,6 +198,16 @@ void       g_allocator_free    (GAllocator   *allocator);
 #define	G_ALLOCATOR_NODE       (3)
 #endif /* G_DISABLE_DEPRECATED */
 
+
+void       g_mem_shutdown                   (void);
+gpointer   g_mem_free_at_shutdown           (gpointer           mem);
+gpointer   g_mem_slice_free_at_shutdown     (gsize              block_size,
+                                             gpointer           mem_block);
+gpointer   g_mem_notify_at_shutdown         (gpointer           user_data,
+                                             GDestroyNotify     callback);
+void       g_mem_remove_notify_at_shutdown (gpointer           user_data,
+                                            GDestroyNotify     callback);
+
 G_END_DECLS
 
 #endif /* __G_MEM_H__ */
diff --git a/glib/gthread.c b/glib/gthread.c
index 2a00c60..140c331 100644
--- a/glib/gthread.c
+++ b/glib/gthread.c
@@ -871,6 +871,16 @@ G_LOCK_DEFINE_STATIC (g_thread);
 /* Initialisation {{{1 ---------------------------------------------------- */
 
 #ifdef G_THREADS_ENABLED
+
+/* called on shutdown, must free all allocated data */
+static void
+on_shutdown (gpointer user_data)
+{
+  GRealThread* main_thread = user_data;
+  /* TODO: bail if other threads than this is running */
+  g_thread_cleanup (main_thread);
+}
+
 /**
  * g_thread_init:
  * @vtable: a function table of type #GThreadFunctions, that provides
@@ -946,6 +956,8 @@ g_thread_init_glib (void)
 #ifdef G_OS_WIN32
   _g_win32_thread_init ();
 #endif
+
+  g_mem_notify_at_shutdown (main_thread, on_shutdown);
 }
 #endif /* G_THREADS_ENABLED */
 
diff --git a/glib/gutils.c b/glib/gutils.c
index 406b4b1..74bc6d3 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -2883,7 +2883,10 @@ read_aliases (gchar *file)
   char buf[256];
   
   if (!alias_table)
-    alias_table = g_hash_table_new (g_str_hash, g_str_equal);
+    {
+      alias_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+      g_mem_notify_at_shutdown (alias_table, (GDestroyNotify) g_hash_table_destroy);
+    }
   fp = fopen (file,"r");
   if (!fp)
     return;
diff --git a/gobject/gparam.c b/gobject/gparam.c
index b1a871e..dcf51ba 100644
--- a/gobject/gparam.c
+++ b/gobject/gparam.c
@@ -1389,7 +1389,7 @@ g_param_type_register_static (const gchar              *name,
   info.instance_size = pspec_info->instance_size;
   info.n_preallocs = pspec_info->n_preallocs;
   info.instance_init = (GInstanceInitFunc) pspec_info->instance_init;
-  cinfo = g_new (ParamSpecClassInfo, 1);
+  cinfo = g_mem_free_at_shutdown (g_new (ParamSpecClassInfo, 1));
   cinfo->value_type = pspec_info->value_type;
   cinfo->finalize = pspec_info->finalize;
   cinfo->value_set_default = pspec_info->value_set_default ? pspec_info->value_set_default : default_value_set_default;
diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c
index 9e07cfe..ebdbfb7 100644
--- a/gobject/gparamspecs.c
+++ b/gobject/gparamspecs.c
@@ -1159,12 +1159,21 @@ param_variant_values_cmp (GParamSpec   *pspec,
 /* --- type initialization --- */
 GType *g_param_spec_types = NULL;
 
+static void
+on_shutdown (gpointer user_data)
+{
+  g_free (g_param_spec_types);
+  g_param_spec_types = NULL;
+}
+
 void
 g_param_spec_types_init (void)	
 {
   const guint n_types = 23;
   GType type, *spec_types, *spec_types_bound;
 
+  g_mem_notify_at_shutdown (NULL, on_shutdown);
+
   g_param_spec_types = g_new0 (GType, n_types);
   spec_types = g_param_spec_types;
   spec_types_bound = g_param_spec_types + n_types;
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index df5a37b..44ca846 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -764,6 +764,26 @@ signal_key_cmp (gconstpointer node1,
     return G_BSEARCH_ARRAY_CMP (key1->itype, key2->itype);
 }
 
+static void
+on_shutdown (gpointer user_data)
+{
+  if (g_handler_list_bsa_ht != NULL)
+    {
+      /* TODO: free elements? */
+      g_hash_table_destroy (g_handler_list_bsa_ht);
+      g_handler_list_bsa_ht = NULL;
+    }
+
+  if (g_signal_key_bsa != NULL)
+    {
+      g_bsearch_array_free (g_signal_key_bsa, &g_signal_key_bconfig);
+      g_signal_key_bsa = NULL;
+    }
+
+  /* TODO: free elements? */
+  g_free (g_signal_nodes);
+}
+
 void
 g_signal_init (void)
 {
@@ -778,6 +798,7 @@ g_signal_init (void)
       g_n_signal_nodes = 1;
       g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
       g_signal_nodes[0] = NULL;
+      g_mem_notify_at_shutdown (NULL, on_shutdown);
     }
   SIGNAL_UNLOCK ();
 }
diff --git a/gobject/gtype.c b/gobject/gtype.c
index bf89d91..4cfc770 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -224,6 +224,18 @@ typedef enum
 } InitState;
 
 /* --- structures --- */
+typedef struct _QData QData;
+struct _GData
+{
+  guint  n_qdatas;
+  QData *qdatas;
+};
+struct _QData
+{
+  GQuark   quark;
+  gpointer data;
+};
+
 struct _TypeNode
 {
   guint volatile ref_count;
@@ -382,6 +394,7 @@ static GQuark          static_quark_type_flags = 0;
 static GQuark          static_quark_iface_holder = 0;
 static GQuark          static_quark_dependants_array = 0;
 GTypeDebugFlags	       _g_type_debug_flags = 0;
+static gboolean        is_shutting_down = FALSE;
 
 /* --- type nodes --- */
 static GHashTable       *static_type_nodes_ht = NULL;
@@ -2308,9 +2321,9 @@ static void
 type_data_last_unref_Wm (TypeNode *node,
 			 gboolean  uncached)
 {
-  g_return_if_fail (node != NULL && node->plugin != NULL);
-  
-  if (!node->data || NODE_REFCOUNT (node) == 0)
+  g_return_if_fail (node != NULL);// && node->plugin != NULL);
+ 
+  if (/*!node->data ||*/ NODE_REFCOUNT (node) == 0)
     {
       g_warning ("cannot drop last reference to unreferenced type `%s'",
 		 NODE_NAME (node));
@@ -2391,10 +2404,28 @@ type_data_last_unref_Wm (TypeNode *node,
       g_free (tdata);
       
       G_WRITE_UNLOCK (&type_rw_lock);
-      g_type_plugin_unuse (node->plugin);
+      if (node->plugin)
+        g_type_plugin_unuse (node->plugin);
       if (ptype)
 	type_data_unref_U (lookup_type_node_I (ptype), FALSE);
       G_WRITE_LOCK (&type_rw_lock);
+
+      g_free (node->children);
+      g_free (node->prerequisites);
+      if (node->global_gdata != NULL)
+        {
+          g_free (node->global_gdata->qdatas);
+          g_free (node->global_gdata);
+        }
+      if (node->n_supers > 0)
+        {
+          g_free (node);
+        }
+      else
+        {
+          node = G_STRUCT_MEMBER_P (node, -SIZEOF_FUNDAMENTAL_INFO);
+          g_free (node);
+        }
     }
 }
 
@@ -2409,14 +2440,14 @@ type_data_unref_U (TypeNode *node,
 
     if (current <= 1)
     {
-      if (!node->plugin)
+      if (!node->plugin && !is_shutting_down)
 	{
 	  g_warning ("static type `%s' unreferenced too often",
 		     NODE_NAME (node));
 	  return;
 	}
 
-      g_assert (current > 0);
+      g_assert (is_shutting_down || current > 0);
 
       g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
       G_WRITE_LOCK (&type_rw_lock);
@@ -2683,6 +2714,14 @@ g_type_register_static_simple (GType             parent_type,
   return g_type_register_static (parent_type, type_name, &info, flags);
 }
 
+static void
+on_shutdown_free_node (gpointer user_data)
+{
+  TypeNode *node = user_data;
+  is_shutting_down = TRUE;
+  type_data_unref_U (node, FALSE);
+}
+
 /**
  * g_type_register_static:
  * @parent_type: Type from which this type will be derived.
@@ -2732,6 +2771,7 @@ g_type_register_static (GType            parent_type,
       type = NODE_TYPE (node);
       type_data_make_W (node, info,
 			check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
+      g_mem_notify_at_shutdown (node, on_shutdown_free_node);
     }
   G_WRITE_UNLOCK (&type_rw_lock);
   
@@ -3583,18 +3623,6 @@ g_type_interfaces (GType  type,
     }
 }
 
-typedef struct _QData QData;
-struct _GData
-{
-  guint  n_qdatas;
-  QData *qdatas;
-};
-struct _QData
-{
-  GQuark   quark;
-  gpointer data;
-};
-
 static inline gpointer
 type_get_qdata_L (TypeNode *node,
 		  GQuark    quark)
@@ -4233,6 +4261,25 @@ _g_type_boxed_init (GType          type,
   node->data->boxed.free_func = free_func;
 }
 
+/* called on shutdown, must free all allocated data */
+static void
+on_shutdown_free_type_system (gpointer user_data)
+{
+  gint n;
+
+  is_shutting_down = TRUE;
+
+  g_hash_table_destroy (static_type_nodes_ht);
+  static_type_nodes_ht = NULL;
+
+  for (n = (G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1; n >= 0; n--)
+    {
+      TypeNode *node = static_fundamental_type_nodes[n];
+      if (node != NULL)
+        type_data_unref_U (node, FALSE);
+    }
+}
+
 /* --- initialization --- */
 /**
  * g_type_init_with_debug_flags:
@@ -4297,6 +4344,7 @@ g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
   /* void type G_TYPE_NONE
    */
   node = type_node_fundamental_new_W (G_TYPE_NONE, g_intern_static_string ("void"), 0);
+  g_atomic_int_set ((int *) &node->ref_count, 1);
   votype = NODE_TYPE (node);
   g_assert (votype == G_TYPE_NONE);
   
@@ -4348,6 +4396,8 @@ g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
    */
   g_signal_init ();
   
+  g_mem_notify_at_shutdown (NULL, on_shutdown_free_type_system);
+
   G_UNLOCK (type_init_lock);
 }
 
diff --git a/gobject/gvalue.c b/gobject/gvalue.c
index 9247d4c..e309158 100644
--- a/gobject/gvalue.c
+++ b/gobject/gvalue.c
@@ -138,10 +138,18 @@ static GBSearchConfig transform_bconfig = {
 
 
 /* --- functions --- */
+static void
+on_shutdown (gpointer user_data)
+{
+  g_bsearch_array_free (transform_array, &transform_bconfig);
+  transform_array = NULL;
+}
+
 void
 g_value_c_init (void)
 {
   transform_array = g_bsearch_array_create (&transform_bconfig);
+  g_mem_notify_at_shutdown (NULL, on_shutdown);
 }
 
 static inline void		/* keep this function in sync with gvaluecollector.h and gboxed.c */
diff --git a/gthread/gthread-posix.c b/gthread/gthread-posix.c
index 9188f84..f8b3475 100644
--- a/gthread/gthread-posix.c
+++ b/gthread/gthread-posix.c
@@ -159,7 +159,7 @@ g_thread_impl_init(void)
 static GMutex *
 g_mutex_new_posix_impl (void)
 {
-  GMutex *result = (GMutex *) g_new (pthread_mutex_t, 1);
+  GMutex *result = (GMutex *) g_mem_free_at_shutdown (g_new (pthread_mutex_t, 1));
   posix_check_cmd (pthread_mutex_init ((pthread_mutex_t *) result,
 				       mutexattr_default));
   return result;
@@ -201,7 +201,7 @@ g_mutex_trylock_posix_impl (GMutex * mutex)
 static GCond *
 g_cond_new_posix_impl (void)
 {
-  GCond *result = (GCond *) g_new (pthread_cond_t, 1);
+  GCond *result = (GCond *) g_mem_free_at_shutdown (g_new (pthread_cond_t, 1));
   posix_check_cmd (pthread_cond_init ((pthread_cond_t *) result,
 				      condattr_default));
   return result;
@@ -265,7 +265,7 @@ g_cond_free_posix_impl (GCond * cond)
 static GPrivate *
 g_private_new_posix_impl (GDestroyNotify destructor)
 {
-  GPrivate *result = (GPrivate *) g_new (pthread_key_t, 1);
+  GPrivate *result = (GPrivate *) g_mem_free_at_shutdown (g_new (pthread_key_t, 1));
   posix_check_cmd (pthread_key_create ((pthread_key_t *) result, destructor));
   return result;
 }
