Python

Stop Memory Leaks in Python with weakref

Learn how Python's weakref module eliminates memory leaks caused by circular references. This guide covers real caching scenarios, the callback trick, and when to use weakref for cleaner memory management.

July 2026 4 min read 12 views 0 hearts

Memory leaks in Python are sneaky. You write code, it works fine, but over time your application starts eating up more and more RAM until it crashes. I've seen this happen at PythonSkillset.com with long-running services, and the culprit is often circular references that the garbage collector can't handle.

Here's the thing most Python developers don't realize – Python's reference counting normally cleans up unused objects immediately. But when objects reference each other in a loop, those reference counts never drop to zero. The garbage collector eventually catches them, but it runs periodically, not instantly. In a tight loop, this can cause memory to balloon.

Where memory leaks actually happen

Let me show you a real scenario. Say you're building a caching system for your web application:

class PageCache:
    def __init__(self):
        self.cache = {}

    def add_page(self, page):
        self.cache[page.url] = page
        page.cache = self  # Circular reference!

That page.cache = self creates a circular reference. The PageCache holds a reference to the page, and the page holds a reference back to the cache. Neither can be freed.

How weakref solves this

The weakref module lets you hold a reference to an object without increasing its reference count. When the object is destroyed, the weak reference just returns None.

Here's the same cache using weakref:

import weakref

class PageCache:
    def __init__(self):
        self.cache = {}

    def add_page(self, page):
        self.cache[page.url] = weakref.ref(page)

    def get_page(self, url):
        ref = self.cache.get(url)
        if ref:
            page = ref()
            if page is not None:
                return page
            else:
                # Page was garbage collected
                del self.cache[url]
        return None

Now the cache doesn't prevent the page from being cleaned up. The cache holds a weak reference, and when the page is no longer needed elsewhere, it gets freed properly.

When to actually use weakref

You don't need weakref for everything. Here's where it makes sense:

  • Caches – You want cached items to be freed when memory is needed
  • Observer patterns – The subject shouldn't prevent observers from being garbage collected
  • Large data structures – Trees or graphs where child nodes reference parents
  • Memory-sensitive applications – Long-running services, mobile apps, embedded systems

The callback trick

weakref has another superpower – you can attach a callback when the object is about to be destroyed:

def cache_cleanup(url):
    print(f"Cleaning up cache entry for {url}")

class Page:
    pass

page = Page()
ref = weakref.ref(page, lambda r: cache_cleanup("example.com/page1"))

This fires automatically when the page is garbage collected. Perfect for cache invalidation.

What about normal references?

Most of the time, Python handles memory fine. Use weakref only when you have circular references or want optional references that don't keep objects alive. Overusing weakref can make code harder to debug since objects disappear unexpectedly.

The final word

Memory leaks in Python usually aren't from bugs – they're from design patterns that create unintended object retention. weakref gives you fine-grained control over this. Use it for caches, callbacks, and any situation where you want to say "I'd like to use this object, but I don't want to keep it alive."

At PythonSkillset.com, we've cut memory usage in half on some services just by switching cache references to weakref. It's not magic – it's just understanding how Python manages memory, and using the right tool for the job.

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.