To profile Python memory usage without changing a single line of code, attach OpenResty XRay to the running process. Its Python GC object memory distribution flame graph — one we invented ourselves — pinpoints exactly which objects, modules, and dictionaries hold the most RAM, and reports the full data reference path to each one.

Below, we run this analysis live on an unmodified gunicorn process — no @profile decorators, no restarts — and then show the automatic reports that keep surfacing memory hogs for you. Memory leaks and large memory footprints are no longer a myth in your Python code!

Find which Python process is using the most memory

Run the top command to check memory usage. As shown, the Python gunicorn process is using the most memory — more than 600MB of RSS.

top output showing the gunicorn Python process using the most memory, over 600MB RSS

Run ps for more details. Here it is the standard Python 3 binary (/usr/bin/python3) that ships with the Linux distribution, running gunicorn for an order_service WSGI application.

ps output showing the gunicorn process runs the standard /usr/bin/python3 binary

Profile Python memory with guided analysis: find the largest objects and their modules

Use OpenResty XRay to inspect this unmodified process in real time. Open the web console, make sure you are watching the right machine, and go to the Guided Analysis page, where you can pick from the types of problems OpenResty XRay can diagnose.

OpenResty XRay Guided Analysis problem types, including High memory usage

Select High memory usage, choose the Python application and the gunicorn process that top flagged (the one using almost 600MB), keep both Python and C/C++ language levels, and start. After a round or two of analysis, OpenResty XRay automatically produces a report.

This is the type of problem we are analyzing now: memory.

The problem type under analysis in the OpenResty XRay report: High memory usage

We can see most of the memory is allocated by the libc allocator. It’s more than 580 MB.

The report showing most memory is allocated by the libc allocator, more than 580MB

This is the Python GC object reference path occupying the most memory. Obviously, this Python VM uses the libc allocator to request memory.

OpenResty XRay report showing the #1 hottest Python GC object reference path: a 570MB dict held by order_name_cache in the prev_processor module

This is the Python dictionary holding all the loaded Python modules.

The Python dictionary that holds all loaded Python modules

Here is the Python module named order_service.service.order.prev_processor.

The Python module order_service.service.order.prev_processor in the reference path

Inside this module, there is a field named order_name_cache.

The order_name_cache field inside the prev_processor module

And this field value is a Python dictionary.

The value of the order_name_cache field is a Python dictionary

Click to see more details.

Click to expand more details of the order_name_cache dictionary

This GC object reference path is automatically inferred from this Python-land GC object memory distribution flame graph.

Python-land GC object memory distribution flame graph highlighting the hottest backtrace down to order_name_cache

Below are more detailed explanations and suggestions regarding the current issue. It talks about the prev_processor module we saw earlier.

OpenResty XRay report explanation breaking down the Python reference path down to the order_name_cache dictionary

It also mentions the order_name_cache dictionary.

Let’s go back to the data reference path. Click the icon to copy the module name.

Clicking the icon on the data reference path to copy the module name

On the terminal, use the find command to find the Python source file.

Using the find command in the terminal to locate the Python source file

Paste the module name we just copied. Here we abuse the dots in the module name as a wildcard for the grep command.

Pasting the module name and using its dots as grep wildcards

Copy the full file path. Use the vim editor to open the source file. You can use any editor you like.

Copying the full file path and opening the source file in vim

We can find the order_name_cache field variable mentioned in the previous report.

Finding the order_name_cache variable mentioned in the report inside the source file

We can also examine how this field variable is being used, to determine if there is a memory leak.

prev_processor.py source showing order_name_cache is a module-level dict that handle() writes to for every order without eviction

order_name_cache is a module-level dictionary that handle() writes a new entry into for every order it processes, and nothing ever removes entries. That unbounded growth is exactly what makes the process hold hundreds of megabytes — a classic Python memory leak you can now fix at its source.

Automatically monitor Python memory usage with scheduled reports

OpenResty XRay can also monitor online processes automatically and show analysis reports. On the Insights page you can find daily and weekly reports — the same memory reference paths surface on their own — so you don’t have to run the Guided Analysis manually, though Guided Analysis is still useful for application development and demonstration purposes.

OpenResty XRay Insights daily report surfacing the top Python memory reference paths automatically

This walkthrough targets a large but stable memory footprint. If your Python process instead keeps growing over time, that points to a leak — our guide explains how to tell a memory leak from high memory usage.

Frequently Asked Questions

How do you find which Python process uses the most memory?

Run top to rank processes by resident memory, then run ps to confirm the exact binary and application. In this tutorial the gunicorn worker running the order_service WSGI app showed over 600 MB of RSS — making it the clear target for deeper profiling.

Can you profile Python memory without adding @profile decorators or restarting the process?

Yes. OpenResty XRay attaches to an already-running, unmodified Python process in real time. There are no @profile decorators to insert and no restarts — the analysis runs against the live process as-is.

What is a Python GC object memory distribution flame graph?

It is a flame graph invented by OpenResty that maps every garbage-collected Python object by how much memory it holds and along which data reference path. OpenResty XRay generates it automatically from a live process and traces each object back through the module hierarchy — for example, from the top-level .modules dictionary down to prev_processor.order_name_cache.

How do you find the largest Python object in memory?

Start a Guided Analysis in OpenResty XRay and select High memory usage. The resulting report ranks GC object reference paths by size. In this case the hottest path led to a single dictorder_name_cache inside the order_service.service.order.prev_processor module — holding roughly 570 MB because handle() writes a new entry for every order it processes and nothing ever removes them.

What kind of memory problems can the GC object flame graph reveal?

The flame graph shows the full data reference path to each object, so it surfaces both large footprints and leaks. In this tutorial, the path revealed that order_name_cache is a module-level dictionary that handle() keeps writing into without ever evicting entries — a classic unbounded-growth memory leak. Because OpenResty XRay attributes the memory to a specific field inside a specific module, you can open the source file directly and see how the variable is used.

What is OpenResty XRay

OpenResty XRay is a dynamic-tracing product that automatically analyzes your running applications to troubleshoot performance problems, behavioral issues, and security vulnerabilities with actionable suggestions. Under the hood, OpenResty XRay is powered by our Y language targeting various runtimes like Stap+, eBPF+, GDB, and ODB, depending on the contexts.

If you like this tutorial, please subscribe to this blog site and/or our YouTube channel. Thank you!

About The Author

Yichun Zhang (Github handle: agentzh), is the original creator of the OpenResty® open-source project and the CEO of OpenResty Inc..

Yichun is one of the earliest advocates and leaders of “open-source technology”. He worked at many internationally renowned tech companies, such as Cloudflare, Yahoo!. He is a pioneer of “edge computing”, “dynamic tracing” and “machine coding”, with over 22 years of programming and 16 years of open source experience. Yichun is well-known in the open-source space as the project leader of OpenResty®, adopted by more than 40 million global website domains.

OpenResty Inc., the enterprise software start-up founded by Yichun in 2017, has customers from some of the biggest companies in the world. Its flagship product, OpenResty XRay, is a non-invasive profiling and troubleshooting tool that significantly enhances and utilizes dynamic tracing technology. And its OpenResty Edge product is a powerful distributed traffic management and private CDN software product.

As an avid open-source contributor, Yichun has contributed more than a million lines of code to numerous open-source projects, including Linux kernel, Nginx, LuaJIT, GDB, SystemTap, LLVM, Perl, etc. He has also authored more than 60 open-source software libraries.