diff --git a/Src/mem.c b/Src/mem.c
index 68bd767..63a5afe 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -294,7 +294,7 @@ pushheap(void)
 #endif
 
     for (h = heaps; h; h = h->next) {
-	DPUTS(!h->used && h->next, "BUG: empty heap");
+	DPUTS(!h->used, "BUG: empty heap");
 	hs = (Heapstack) zalloc(sizeof(*hs));
 	hs->next = h->sp;
 	h->sp = hs;
@@ -334,15 +334,17 @@ freeheap(void)
      *
      * Whenever fheap is NULL here, the loop below sweeps back over the
      * entire heap list again, resetting the free space in every arena to
-     * the amount stashed by pushheap() and finding the arena with the most
+     * the amount stashed by pushheap() and finding the first arena with
      * free space to optimize zhalloc()'s next search.  When there's a lot
      * of stuff already on the heap, this is an enormous amount of work,
      * and performance goes to hell.
      *
-     * Therefore, we defer freeing the most recently allocated arena until
-     * we reach popheap().  This may fail to reclaim some space in earlier
-     * arenas.
-     *
+     * However, if the arena to which fheap points is unused, we want to
+     * free it, so we have no choice but to do the sweep for a new fheap.
+     */
+    if (fheap && !fheap->sp)
+	fheap = NULL;	/* We used to do this unconditionally */
+    /*
      * In other cases, either fheap is already correct, or it has never
      * been set and this loop will do it, or it'll be reset from scratch
      * on the next popheap().  So all that's needed here is to pick up
@@ -359,11 +361,7 @@ freeheap(void)
 	    memset(arena(h) + h->sp->used, 0xff, h->used - h->sp->used);
 #endif
 	    h->used = h->sp->used;
-	    if (!fheap) {
-		if (h->used < ARENA_SIZEOF(h))
-		    fheap = h;
-	    } else if (ARENA_SIZEOF(h) - h->used >
-		       ARENA_SIZEOF(fheap) - fheap->used)
+	    if (!fheap && h->used < ARENA_SIZEOF(h))
 		fheap = h;
 	    hl = h;
 #ifdef ZSH_HEAP_DEBUG
@@ -386,26 +384,6 @@ freeheap(void)
 	    VALGRIND_MEMPOOL_TRIM((char *)h, (char *)arena(h), h->used);
 #endif
 	} else {
-	    if (fheap == h)
-		fheap = NULL;
-	    if (h->next) {
-		/* We want to cut this out of the arena list if we can */
-		if (h == heaps)
-		    hl = heaps = h->next;
-		else if (hl && hl->next == h)
-		    hl->next = h->next;
-		else {
-		    DPUTS(hl, "hl->next != h when freeing");
-		    hl = h;
-		    continue;
-		}
-		h->next = NULL;
-	    } else {
-		/* Leave an empty arena at the end until popped */
-		h->used = 0;
-		fheap = hl = h;
-		break;
-	    }
 #ifdef USE_MMAP
 	    munmap((void *) h, h->size);
 #else
@@ -463,29 +441,12 @@ popheap(void)
 #ifdef ZSH_VALGRIND
 	    VALGRIND_MEMPOOL_TRIM((char *)h, (char *)arena(h), h->used);
 #endif
-	    if (!fheap) {
-		if (h->used < ARENA_SIZEOF(h))
-		    fheap = h;
-	    } else if (ARENA_SIZEOF(h) - h->used >
-		       ARENA_SIZEOF(fheap) - fheap->used)
+	    if (!fheap && h->used < ARENA_SIZEOF(h))
 		fheap = h;
 	    zfree(hs, sizeof(*hs));
 
 	    hl = h;
 	} else {
-	    if (h->next) {
-		/* We want to cut this out of the arena list if we can */
-		if (h == heaps)
-		    hl = heaps = h->next;
-		else if (hl && hl->next == h)
-		    hl->next = h->next;
-		else {
-		    DPUTS(hl, "hl->next != h when popping");
-		    hl = h;
-		    continue;
-		}
-		h->next = NULL;
-	    }
 #ifdef USE_MMAP
 	    munmap((void *) h, h->size);
 #else
@@ -563,7 +524,7 @@ zheapptr(void *p)
 mod_export void *
 zhalloc(size_t size)
 {
-    Heap h, hp = NULL;
+    Heap h;
     size_t n;
 #ifdef ZSH_VALGRIND
     size_t req_size = size;
@@ -590,7 +551,6 @@ zhalloc(size_t size)
      * so why start over at heaps just because fheap has too little?
      */
     for (h = (fheap ? fheap : heaps); h; h = h->next) {
-	hp = h;
 	if (ARENA_SIZEOF(h) >= (n = size + h->used)) {
 	    void *ret;
 
@@ -611,6 +571,7 @@ zhalloc(size_t size)
 	}
     }
     {
+	Heap hp;
         /* not found, allocate new heap */
 #if defined(ZSH_MEM) && !defined(USE_MMAP)
 	static int called = 0;
@@ -619,6 +580,7 @@ zhalloc(size_t size)
 #endif
 
 	n = HEAP_ARENA_SIZE > size ? HEAPSIZE : size + sizeof(*h);
+	for (hp = NULL, h = heaps; h; hp = h, h = h->next);
 
 #ifdef USE_MMAP
 	h = mmap_heap_alloc(&n);
@@ -650,7 +612,6 @@ zhalloc(size_t size)
 	VALGRIND_MEMPOOL_ALLOC((char *)h, (char *)arena(h), req_size);
 #endif
 
-	DPUTS(hp && hp->next, "failed to find end of chain in zhalloc");
 	if (hp)
 	    hp->next = h;
 	else
