summaryrefslogtreecommitdiff
path: root/Objects/obmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/obmalloc.c')
-rw-r--r--Objects/obmalloc.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index fc7bef6199..622da3ad08 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -1758,7 +1758,12 @@ pymalloc_free(void *ctx, void *p)
/* All the rest is arena management. We just freed
* a pool, and there are 4 cases for arena mgmt:
* 1. If all the pools are free, return the arena to
- * the system free().
+ * the system free(). Except if this is the last
+ * arena in the list, keep it to avoid thrashing:
+ * keeping one wholly free arena in the list avoids
+ * pathological cases where a simple loop would
+ * otherwise provoke needing to allocate and free an
+ * arena on every iteration. See bpo-37257.
* 2. If this is the only free pool in the arena,
* add the arena back to the `usable_arenas` list.
* 3. If the "next" arena has a smaller count of free
@@ -1767,7 +1772,7 @@ pymalloc_free(void *ctx, void *p)
* nfreepools.
* 4. Else there's nothing more to do.
*/
- if (nf == ao->ntotalpools) {
+ if (nf == ao->ntotalpools && ao->nextarena != NULL) {
/* Case 1. First unlink ao from usable_arenas.
*/
assert(ao->prevarena == NULL ||