GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Free threading memory leak · Issue #145615 · python/cpython

Free threading memory leak #145615

New issue
Copy link
New issue
Copy link
Closed
Closed
Free threading memory leak#145615
Copy link
Labels
3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixestopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@colesbury
colesbury
opened on Mar 7, 2026
Issue body actions

This bug was originally found by a colleague. Memory usage (RSS) keeps increasing even though allocated blocks stays essentially constant. Self contained reproducer below:

import gc
import sys
import os
import concurrent.futures

def get_rss_mb():
    with open("/proc/self/statm") as f:
        return int(f.read().split()[1]) * os.sysconf("SC_PAGE_SIZE") / (1024 * 1024)

def work(_):
    return [bytearray(64) for _ in range(4000)]


NUM_ITERATIONS = int(sys.argv[1]) if len(sys.argv) > 1 else 20

pool = concurrent.futures.ThreadPoolExecutor(max_workers=4)
for i in range(NUM_ITERATIONS):
    futures = [pool.submit(work, j) for j in range(100)]
    results = [f.result() for f in futures]
    del futures, results  # free worker-allocated objects on main thread
    gc.collect()
    gc.collect()
    blocks = sys.getallocatedblocks()
    print(f"iter {i:3d}: RSS={get_rss_mb():7.1f} MB {blocks=}")

pool.shutdown()
print(f"after shutdown: RSS={get_rss_mb():7.1f} MB")

The problem is that we end up having orphaned mimalloc pages in the full queue, even though those pages have available blocks or are completely empty. They're "leaked" until the thread exits.

NOTE: The bugs are limited out our mimalloc modifications. They're not in upstream mimalloc.

I think there are at least two underlying bugs here:

  1. _PyMem_mi_page_maybe_free leaves empty pages in the full page queue. This bug can happen when a page goes from "full" to "all free".
  2. _mi_page_free_collect calls _PyMem_mi_page_clear_qsbr if page->local_free != NULL. This can get erroneously triggered even the by traversing heaps. We only want to clear the page QSBR counter when it becomes empty again.

Additionally, _PyMem_mi_page_maybe_free can insert pages into the wrong mimalloc list. _PyMem_mi_page_maybe_free inserts the page into the current thread's list. However, during GC and other stop-the-world pauses, we may traverse the heaps of other threads. That traversal does some processing of free lists, which can end up calling _PyMem_mi_page_maybe_free. In that case, we should insert the page into the owning thread's list, not the current thread's list. Otherwise, we can end up with a data race later on.

Linked PRs

  • gh-145615: Fix mimalloc page leak in the free-threaded build #145626
  • [3.14] gh-145615: Fix mimalloc page leak in the free-threaded build (gh-145626) #145691

Activity

  1. colesbury
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    topic-free-threading
    3.14bugs and security fixesbugs and security fixes
    3.15bugs and security fixesbugs and security fixes
    on Mar 7, 2026
  2. Krishna-web-hub commented on Mar 7, 2026

    @Krishna-web-hub
    Krishna-web-hub
    on Mar 7, 2026
    Contributor
    More actions

    hey @colesbury, I was looking through this issue and also tried to regenerate the bug but cannot reproduce the bug as per your code mentioned.

  3. colesbury
    added a commit that references this issue on Mar 7, 2026

    pythongh-145615: Fix mimalloc page leak in the free-threaded build

    218b6bf
  4. colesbury
    marked _PyMem_mi_page_maybe_free may insert pages into wrong thread's list #145614 as a duplicate of this issue on Mar 7, 2026
  5. colesbury
    added a commit that references this issue on Mar 9, 2026

    gh-145615: Fix mimalloc page leak in the free-threaded build (gh-145626)

    d76df75
  6. miss-islington
    added a commit that references this issue on Mar 9, 2026

    pythongh-145615: Fix mimalloc page leak in the free-threaded build (p…

    2a3a642
  7. colesbury
    added a commit that references this issue on Mar 9, 2026

    [3.14] gh-145615: Fix mimalloc page leak in the free-threaded build (g…

    ba1ea3a
  8. colesbury
    closed this as completedon Mar 9, 2026
  9. ljfp
    added a commit that references this issue on Apr 25, 2026

    pythongh-145615: Fix mimalloc page leak in the free-threaded build (p…

    581c0ab
  10. corona10
    added 2 commits that reference this issue on Oct 10, 2026

    Re-apply CPython-specific changes to mimalloc v2.5.2

    fa3a143

    Re-apply CPython-specific changes to mimalloc v2.5.2

    836dced
  11. corona10
    added 2 commits that reference this issue on Oct 22, 2026

    gh-159111: Update vendored mimalloc to v2.5.2 (gh-159112)

    aff7a2e

    [3.15] pythongh-159111: Update vendored mimalloc to v2.5.2 (pythongh-…

    265f0fb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixestopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.