diff --git a/src/block_allocator.c b/src/block_allocator.c
index de8b96931ee559529c4a080bb71b2a5bd4ba2313..031675da9303be232a99e3aeb15fa30be0c535e9 100644
--- a/src/block_allocator.c
+++ b/src/block_allocator.c
@@ -46,6 +46,15 @@ struct ba_block_header {
     struct ba_block_header * next;
 };
 
+static INLINE void ba_clear_page(struct block_allocator * a, struct ba_page * p, struct ba_layout * l) {
+    p->h.used = 0;
+    p->h.flags = BA_FLAG_SORTED;
+    p->h.first = BA_BLOCKN(*l, p, 0);
+    PIKE_MEMPOOL_ALLOC(a, p->h.first, l->block_size);
+    p->h.first->next = BA_ONE;
+    PIKE_MEMPOOL_FREE(a, p->h.first, l->block_size);
+}
+
 static struct ba_page * ba_alloc_page(struct block_allocator * a, int i) {
     struct ba_layout l = ba_get_layout(a, i);
     size_t n = l.offset + l.block_size + l.doffset;
@@ -66,16 +75,32 @@ static struct ba_page * ba_alloc_page(struct block_allocator * a, int i) {
 	p = (struct ba_page*)xalloc(n);
 #endif
     }
-    p->h.first = BA_BLOCKN(a->l, p, 0);
-    p->h.first->next = BA_ONE;
-    p->h.used = 0;
+    ba_clear_page(a, p, &a->l);
     PIKE_MEM_NA_RANGE((char*)p + l.doffset, n - l.doffset);
     return p;
 }
 
+static void ba_free_empty_pages(struct block_allocator * a) {
+    int i = a->size - 1;
+
+    for (i = a->size - 1; i >= 0; i--) {
+        struct ba_page * p = a->pages[i];
+        if (p->h.used) break;
+#ifdef DEBUG_MALLOC
+        system_free(p);
+#else
+        free(p);
+#endif
+        a->pages[i] = NULL;
+    }
+
+    a->size = i+1;
+    a->alloc = a->last_free = MAXIMUM(0, i);
+}
 
 PMOD_EXPORT void ba_init_aligned(struct block_allocator * a, unsigned INT32 block_size,
 				 unsigned INT32 blocks, unsigned INT32 alignment) {
+    PIKE_MEMPOOL_CREATE(a);
     block_size = MAXIMUM(block_size, sizeof(struct ba_block_header));
     if (alignment) {
 	if (alignment & (alignment - 1))
@@ -96,11 +121,13 @@ PMOD_EXPORT void ba_init_aligned(struct block_allocator * a, unsigned INT32 bloc
     a->l.alignment = alignment;
     memset(a->pages, 0, sizeof(a->pages));
     a->pages[0] = ba_alloc_page(a, 0);
-    PIKE_MEMPOOL_CREATE(a);
 }
 
 PMOD_EXPORT void ba_destroy(struct block_allocator * a) {
     int i;
+
+    if (!a->l.offset) return;
+
     for (i = 0; i < a->size; i++) {
 	if (a->pages[i]) {
 #ifdef DEBUG_MALLOC
@@ -114,6 +141,25 @@ PMOD_EXPORT void ba_destroy(struct block_allocator * a) {
     a->size = 0;
     a->alloc = 0;
     a->last_free = 0;
+    PIKE_MEMPOOL_DESTROY(a);
+}
+
+PMOD_EXPORT void ba_free_all(struct block_allocator * a) {
+    int i;
+    struct ba_layout l;
+
+    if (!a->l.offset) return;
+    if (!a->size) return;
+
+    l = ba_get_layout(a, 0);
+
+    for (i = 0; i < a->size; i++) {
+        struct ba_page * page = a->pages[i];
+        ba_clear_page(a, page, &l);
+        ba_double_layout(&l);
+    }
+    a->alloc = 0;
+    a->last_free = 0;
 }
 
 PMOD_EXPORT size_t ba_count(const struct block_allocator * a) {
@@ -249,19 +295,12 @@ found:
 	    Pike_fatal("freeing from empty page %p\n", p);
 	}
 #endif
-	if (!(--p->h.used) && i+1 == a->size) {
-	    while (i >= 0 && !(p->h.used)) {
-#ifdef DEBUG_MALLOC
-		system_free(p);
-#else
-		free(p);
-#endif
-		a->pages[i] = NULL;
-
-		p = a->pages[--i];
-	    }
-	    a->size = i+1;
-	    a->alloc = a->last_free = MAXIMUM(0, i);
+	if (!(--p->h.used)) {
+            if (i+1 == a->size) {
+                ba_free_empty_pages(a);
+            } else {
+                ba_clear_page(a, p, &l);
+            }
 	}
     }
 #ifdef PIKE_DEBUG
diff --git a/src/block_allocator.h b/src/block_allocator.h
index def2e26deb8fa43009104b3651edeb33d8c6811b..4d6e1229c050d3365a2ca439fee6a012bf609d23 100644
--- a/src/block_allocator.h
+++ b/src/block_allocator.h
@@ -60,6 +60,7 @@ PMOD_EXPORT void ba_init_aligned(struct block_allocator * a, unsigned INT32 bloc
 ATTRIBUTE((malloc)) PMOD_EXPORT void * ba_alloc(struct block_allocator * a);
 PMOD_EXPORT void ba_free(struct block_allocator * a, void * ptr);
 PMOD_EXPORT void ba_destroy(struct block_allocator * a);
+PMOD_EXPORT void ba_free_all(struct block_allocator * a);
 PMOD_EXPORT size_t ba_count(const struct block_allocator * a);
 PMOD_EXPORT void ba_count_all(const struct block_allocator * a, size_t * num, size_t * size);
 
diff --git a/src/gc.c b/src/gc.c
index 111b7878684c06a57799939bccf86a6d3f666a76..0a066c111858affbdbc045a987fc6b95ba286c2b 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -2057,8 +2057,8 @@ void exit_gc(void)
   if (!gc_keep_markers)
     cleanup_markers();
 
-  ba_destroy(&gc_rec_frame_allocator);
-  ba_destroy(&ba_mixed_frame_allocator);
+  ba_free_all(&gc_rec_frame_allocator);
+  ba_free_all(&ba_mixed_frame_allocator);
 
 #ifdef PIKE_DEBUG
   if (gc_is_watching) {
diff --git a/src/pike_memory.h b/src/pike_memory.h
index 8cf0fb1ffe7e5e07e0259ecdee322be88f1cc071..358b064e2cb00ae2e3df9d4bd224063b7196b733 100644
--- a/src/pike_memory.h
+++ b/src/pike_memory.h
@@ -86,14 +86,16 @@
   VALGRIND_CHECK_MEM_IS_DEFINED(addr, bytes)
 
 #ifdef VALGRIND_CREATE_MEMPOOL
-# define PIKE_MEMPOOL_CREATE(a)		VALGRIND_CREATE_MEMPOOL(a, 0, 0)
-# define PIKE_MEMPOOL_ALLOC(a, p, l)	VALGRIND_MEMPOOL_ALLOC(a, p, l)
-# define PIKE_MEMPOOL_FREE(a, p, l)	VALGRIND_MEMPOOL_FREE(a, p)
+# define PIKE_MEMPOOL_CREATE(a)         VALGRIND_CREATE_MEMPOOL(a, 0, 0)
+# define PIKE_MEMPOOL_ALLOC(a, p, l)    VALGRIND_MEMPOOL_ALLOC(a, p, l)
+# define PIKE_MEMPOOL_FREE(a, p, l)     VALGRIND_MEMPOOL_FREE(a, p)
+# define PIKE_MEMPOOL_DESTROY(a)        VALGRIND_DESTROY_MEMPOOL(a)
 #else
 /* somewhat functional alternatives to mempool macros */
 # define PIKE_MEMPOOL_CREATE(a)
 # define PIKE_MEMPOOL_ALLOC(a, p, l)    PIKE_MEM_WO_RANGE(p, l)
-# define PIKE_MEMPOOL_FREE(a, p, l)	PIKE_MEM_NA_RANGE(p, l)
+# define PIKE_MEMPOOL_FREE(a, p, l)     PIKE_MEM_NA_RANGE(p, l)
+# define PIKE_MEMPOOL_DESTROY(a)
 #endif
 
 #else  /* !HAVE_VALGRIND_MACROS */
@@ -114,6 +116,7 @@
 #define PIKE_MEMPOOL_CREATE(a)
 #define PIKE_MEMPOOL_ALLOC(a, p, l)
 #define PIKE_MEMPOOL_FREE(a, p, l)
+#define PIKE_MEMPOOL_DESTROY(a)
 
 #endif	/* !HAVE_VALGRIND_MACROS */