keep max 3 pages as retired
diff --git a/src/page.c b/src/page.c
index 417e100..d315e85 100644
--- a/src/page.c
+++ b/src/page.c
@@ -411,7 +411,8 @@
   // _mi_arenas_collect(false, false, theap->tld);  // allow purging
 }
 
-#define MI_RETIRE_CYCLES      (16)
+#define MI_RETIRE_CYCLES      (16)      /* keep a retired page around for about 16 "cycles" before free'ing it */
+#define MI_RETIRE_MAX_PAGES   (3)       /* keep at most N pages per size bin as retired */
 
 // Retire a page with no more used blocks
 // Important to not retire too quickly though as new
@@ -438,7 +439,7 @@
   #if MI_RETIRE_CYCLES > 0
   const size_t bsize = mi_page_block_size(page);
   if mi_likely( /* bsize < MI_MAX_RETIRE_SIZE && */ !mi_page_queue_is_special(pq)) {  // not full or huge queue?
-    if (pq->last==page && pq->first==page) { // the only page in the queue?
+    if (pq->count <= MI_RETIRE_MAX_PAGES) { // at most N pages left?  // pq->last==page && pq->first==page) { // the only page in the queue?
       mi_theap_t* theap = mi_page_theap(page);
       mi_theap_stat_counter_increase(theap, pages_retire, 1);
       page->retire_expire = (bsize <= MI_SMALL_MAX_OBJ_SIZE ? MI_RETIRE_CYCLES : MI_RETIRE_CYCLES/4);
@@ -477,29 +478,35 @@
   }
 }
 
+static void mi_page_try_retire(mi_page_queue_t* pq, mi_page_t* page, size_t bin, bool force, size_t* min, size_t* max) {    
+  if (mi_page_all_free(page)) {
+    page->retire_expire--;
+    if (page->retire_expire == 0 || force) {
+      _mi_page_free(page, pq);
+    }
+    else {
+      // keep retired, update min/max
+      if (bin < *min) *min = bin;
+      if (bin > *max) *max = bin;
+    }
+  }
+  else {
+    page->retire_expire = 0;
+  }  
+}
+
 // free retired pages: we don't need to look at the entire queues
 // since we only retire pages that are at the head position in a queue.
 void _mi_theap_collect_retired(mi_theap_t* theap, bool force) {
   size_t min = MI_BIN_FULL;
   size_t max = 0;
   for(size_t bin = theap->page_retired_min; bin <= theap->page_retired_max; bin++) {
-    mi_page_queue_t* pq   = &theap->pages[bin];
-    mi_page_t*       page = pq->first;
-    if (page != NULL && page->retire_expire != 0) {
-      if (mi_page_all_free(page)) {
-        page->retire_expire--;
-        if (page->retire_expire == 0 || force) {
-          _mi_page_free(page, pq);
-        }
-        else {
-          // keep retired, update min/max
-          if (bin < min) min = bin;
-          if (bin > max) max = bin;
-        }
-      }
-      else {
-        page->retire_expire = 0;
-      }
+    mi_page_queue_t* pq  = &theap->pages[bin];
+    mi_page_t* page      = pq->first;
+    for (int i = 0; i<MI_RETIRE_MAX_PAGES && page!=NULL && page->retire_expire==0; i++) {
+      mi_page_t* next = page-> next;
+      mi_page_try_retire(pq,page,bin,force,&min,&max);
+      page = next;
     }
   }
   theap->page_retired_min = min;