diff --git a/glib/ghash.c b/glib/ghash.c
index 492aa20..117ef5f 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -454,8 +454,9 @@ g_hash_table_remove_node (GHashTable   *hash_table,
  * @hash_table: our #GHashTable
  * @notify: %TRUE if the destroy notify handlers are to be called
  *
- * Removes all nodes from the table.  Since this may be a precursor to
- * freeing the table entirely, no resize is performed.
+ * Removes all nodes from the table. Since this may be a precursor to
+ * freeing the table entirely, a resize will only be performed if new
+ * memory has to be allocated.
  *
  * If @notify is %TRUE then the destroy notify functions are called
  * for the key and value of the hash node.
@@ -465,8 +466,10 @@ g_hash_table_remove_all_nodes (GHashTable *hash_table,
                                gboolean    notify)
 {
   int i;
-  gpointer key;
-  gpointer value;
+  gint old_size;
+  gpointer *old_keys;
+  gpointer *old_values;
+  guint    *old_hashes;
 
   hash_table->nnodes = 0;
   hash_table->noccupied = 0;
@@ -482,28 +485,37 @@ g_hash_table_remove_all_nodes (GHashTable *hash_table,
       return;
     }
 
-  for (i = 0; i < hash_table->size; i++)
-    {
-      if (HASH_IS_REAL (hash_table->hashes[i]))
-        {
-          key = hash_table->keys[i];
-          value = hash_table->values[i];
+  /* Replace the current storage space with a new one. Doing this means
+   * that any operation happening from destroy notifiers will be done
+   * on the already empty hash table. */
+  old_size = hash_table->size;
+  old_keys   = hash_table->keys;
+  old_values = hash_table->values;
+  old_hashes = hash_table->hashes;
 
-          hash_table->hashes[i] = UNUSED_HASH_VALUE;
-          hash_table->keys[i] = NULL;
-          hash_table->values[i] = NULL;
+  g_hash_table_set_shift (hash_table, HASH_TABLE_MIN_SHIFT);
+  hash_table->keys   = g_new0 (gpointer, hash_table->size);
+  hash_table->values = hash_table->keys;
+  hash_table->hashes = g_new0 (guint, hash_table->size);
 
+  for (i = 0; i < old_size; i++)
+    {
+      if (HASH_IS_REAL (old_hashes[i]))
+        {
           if (hash_table->key_destroy_func != NULL)
-            hash_table->key_destroy_func (key);
+            hash_table->key_destroy_func (old_keys[i]);
 
           if (hash_table->value_destroy_func != NULL)
-            hash_table->value_destroy_func (value);
-        }
-      else if (HASH_IS_TOMBSTONE (hash_table->hashes[i]))
-        {
-          hash_table->hashes[i] = UNUSED_HASH_VALUE;
+            hash_table->value_destroy_func (old_values[i]);
         }
     }
+
+  /* Destroy old storage space. */
+  if (old_keys != old_values)
+    g_free (old_values);
+
+  g_free (old_keys);
+  g_free (old_hashes);
 }
 
 /*
@@ -640,6 +652,11 @@ g_hash_table_new (GHashFunc  hash_func,
  * allocated for the key and value that get called when removing the
  * entry from the #GHashTable.
  *
+ * Since version 2.35.9 it is permissible for destroy notify functions to modify
+ * the table while they are running. This may be useful for caches, where
+ * further elements can be removed from the destroy handler. Using this feature
+ * to insert new nodes may have undesired side effects.
+ *
  * Return value: a new #GHashTable
  */
 GHashTable *
@@ -1386,7 +1403,7 @@ g_hash_table_steal_all (GHashTable *hash_table)
  * node is removed from the table.
  *
  * If @notify is true then the destroy notify handlers will be called
- * for each removed node.
+ * for each removed node. The call to the destroy notify handlers is delayed.
  */
 static guint
 g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
@@ -1394,12 +1411,24 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
                                       gpointer    user_data,
                                       gboolean    notify)
 {
+  gpointer *deleted_keys = NULL;
+  gpointer *deleted_values = NULL;
   guint deleted = 0;
   gint i;
 #ifndef G_DISABLE_ASSERT
   gint version = hash_table->version;
 #endif
 
+  notify = notify && (hash_table->key_destroy_func || hash_table->value_destroy_func);
+
+  if (notify)
+    {
+      if (hash_table->key_destroy_func)
+        deleted_keys = g_new (gpointer, hash_table->nnodes);
+      if (hash_table->value_destroy_func)
+        deleted_values = g_new (gpointer, hash_table->nnodes);
+    }
+
   for (i = 0; i < hash_table->size; i++)
     {
       guint node_hash = hash_table->hashes[i];
@@ -1409,7 +1438,14 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
       if (HASH_IS_REAL (node_hash) &&
           (* func) (node_key, node_value, user_data))
         {
-          g_hash_table_remove_node (hash_table, i, notify);
+          g_hash_table_remove_node (hash_table, i, FALSE);
+
+          /* Queue key/value for destruction. */
+          if (notify && hash_table->key_destroy_func)
+            deleted_keys[deleted] = node_key;
+          if (notify && hash_table->value_destroy_func)
+            deleted_values[deleted] = node_value;
+
           deleted++;
         }
 
@@ -1418,6 +1454,23 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
 #endif
     }
 
+  if (notify)
+    {
+      for (i = 0; i < deleted; i++)
+        {
+          if (hash_table->key_destroy_func)
+            hash_table->key_destroy_func (deleted_keys[i]);
+          if (hash_table->value_destroy_func)
+            hash_table->value_destroy_func (deleted_values[i]);
+        }
+
+      if (hash_table->key_destroy_func)
+        g_free (deleted_keys);
+      if (hash_table->value_destroy_func)
+        g_free (deleted_values);
+    }
+
+
   g_hash_table_maybe_resize (hash_table);
 
 #ifndef G_DISABLE_ASSERT
@@ -1440,6 +1493,10 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table,
  * value destroy functions when creating the #GHashTable, they are
  * used to free the memory allocated for the removed keys and values.
  *
+ * The hash table may not be modified by the iterator itself. Since
+ * 2.35.9 it is permissible for the destroy notify functions to modify the
+ * hash table while they are running.
+ *
  * See #GHashTableIter for an alternative way to loop over the
  * key/value pairs in the hash table.
  *
