memory management
Python programming
memory allocation
free memory
garbage collection

How can I explicitly free memory in Python?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Python, you usually do not free memory directly the way you would in C. What you can do is remove references to objects so Python can reclaim them, optionally trigger garbage collection for cyclic garbage, and structure your program so large temporary objects die as soon as possible.

What "Freeing Memory" Means in Python

Python manages memory automatically. Most objects are reclaimed when their reference count drops to zero, and the garbage collector handles reference cycles.

So the practical levers you have are:

  • remove references,
  • break cycles,
  • close non-memory resources explicitly,
  • and sometimes call gc.collect() when cyclic garbage matters.

That is different from manually deallocating a block with free().

Use del to Drop References

del does not directly free memory. It removes a name or container entry that points to an object.

python
1data = [0] * 1_000_000
2print(len(data))
3
4del data

If that was the last reference to the list, Python can reclaim the object immediately. If some other variable still points to it, nothing meaningful is freed yet.

That is why this matters:

python
1a = [1, 2, 3]
2b = a
3
4del a
5print(b)

The list still exists because b still refers to it.

Cycles Need Garbage Collection

Reference counting alone cannot reclaim cycles:

python
1class Node:
2    def __init__(self):
3        self.other = None
4
5a = Node()
6b = Node()
7a.other = b
8b.other = a

If both names disappear, the objects may still need cyclic garbage collection.

You can ask for a collection pass:

python
1import gc
2
3del a
4del b
5gc.collect()

This can help in some workloads, but it should not be your first answer to every memory problem.

Free Large Temporaries by Narrowing Scope

Often the best memory technique is to let large objects die naturally by keeping them in a narrow scope.

python
1def process_file(path):
2    with open(path, "rb") as handle:
3        payload = handle.read()
4        # process payload here
5    # payload goes out of scope when the function returns

This is often cleaner than building huge global or long-lived structures and then trying to clean them up later.

Close Resources Explicitly

File handles, sockets, database cursors, and GPU resources are not the same as ordinary Python heap objects. Use context managers or explicit close methods.

python
with open("example.txt", "w", encoding="utf-8") as handle:
    handle.write("hello")

Or:

python
1conn = make_connection()
2try:
3    use(conn)
4finally:
5    conn.close()

If you do not close these resources, you can leak important system capacity even if Python object memory is eventually reclaimed.

Why RSS May Not Drop Immediately

A common surprise is:

  • delete a big object,
  • call gc.collect(),
  • and the process still appears to hold a lot of memory.

This does not always mean the memory is still in use by live Python objects. Python's allocator and the underlying C allocator may keep freed arenas available for reuse rather than returning them immediately to the OS.

So "object was reclaimed" and "process RSS shrank" are related but not identical events.

Use tracemalloc or Profilers Before Guessing

If you think memory is leaking, measure it:

python
1import tracemalloc
2
3tracemalloc.start()
4
5data = [str(i) for i in range(100000)]
6snapshot = tracemalloc.take_snapshot()
7
8for stat in snapshot.statistics("lineno")[:5]:
9    print(stat)

This helps identify where memory is being allocated rather than guessing from process size alone.

For Huge Workloads, Consider Process Isolation

If you truly need memory to be returned decisively, an effective pattern is to do the heavy work in a subprocess and then let that subprocess exit.

That is often more reliable than trying to force a long-running Python process to return every freed page to the operating system exactly when you want.

This is especially useful for:

  • large batch jobs,
  • data conversion tasks,
  • and memory-spiky pipelines.

Common Pitfalls

The biggest pitfall is believing del directly frees memory the way free() does in C. It only removes references.

Another mistake is calling gc.collect() everywhere without understanding whether the problem involves cycles at all.

Developers also often ignore non-memory resources such as files and sockets. Those need explicit closing even though Python manages ordinary object lifetimes.

Finally, do not assume process memory dropping in Task Manager is the only measure of success. Freed Python objects do not always mean immediate RSS reduction.

Summary

  • In Python, you free memory indirectly by removing references.
  • 'del drops names; it does not directly deallocate live objects with remaining references.'
  • 'gc.collect() is mainly relevant for cyclic garbage.'
  • Context managers and explicit close() calls are still important for non-memory resources.
  • For hard memory boundaries, subprocess isolation is often more effective than trying to micromanage a long-lived interpreter.

Course illustration
Course illustration

All Rights Reserved.