Why isn't all memory freed when CPython exits?

CPython is the default and most widely used interpreter or implementation of Python. When CPython exits, it attempts to clean up all allocated memory, but not all memory is freed due to several technical limitations.

Why Memory Isn't Completely Freed

Python is quite serious about cleaning up memory on exit and does try to destroy every single object, but unfortunately objects referenced from the global namespaces of Python modules are not always deallocated when Python exits. The main reasons are:

  • Circular references Objects that reference each other in a loop

  • C library allocations Memory allocated by C extensions that cannot be freed by Python

  • Global namespace objects Objects in module-level scope that persist until exit

The atexit Module

The atexit module allows you to register cleanup functions that execute automatically when the Python interpreter terminates. Functions are executed in reverse order of registration if you register A, B, and C, they will run in the order C, B, A.

Import the atexit module ?

import atexit

Methods of the atexit Module

The atexit module provides two main methods ?

  • atexit.register(func, *args, **kwargs) Register func as a function to be executed at termination. Any optional arguments that are to be passed to func must be passed as arguments to register()

  • atexit.unregister(func) Remove func from the list of functions to be run at interpreter shutdown. unregister() silently does nothing if func was not previously registered

Example: Persistent Counter

Here's a practical example showing how to use atexit to save data before program termination ?

import atexit

try:
    with open('counterfile') as infile:
        _count = int(infile.read())
except FileNotFoundError:
    _count = 0

def incrcounter(n):
    global _count
    _count = _count + n

def savecounter():
    with open('counterfile', 'w') as outfile:
        outfile.write('%d' % _count)

# Register the cleanup function
atexit.register(savecounter)

# Test the counter
incrcounter(5)
print(f"Current count: {_count}")
Current count: 5

How It Works

The above example demonstrates how a module can initialize a counter from a file when it is imported and save the counter's updated value automatically when the program terminates without relying on the application making an explicit call into this module at termination.

Conclusion

CPython doesn't free all memory on exit due to circular references and C library allocations. Use the atexit module to register cleanup functions that ensure critical data is saved before program termination.

Updated on: 2026-03-26T21:48:30+05:30

763 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements