I made some more edits based on dinatrina's answer, and incorporating the not-double-counting from Dara O h's.
This includes special handling for pandas DataFrames. It prints out the types of objects that aren't handled, in case one of them is a container and you're missing big chunks of memory.
import sys
try:
import pandas as pd
has_pandas = True
except ImportError:
has_pandas = False
types_seen = set()
def get_real_size(obj, ids_seen):
"""Recursively calculate the real memory size of an object."""
if obj is types_seen or id(obj) in ids_seen:
return 0, ids_seen
ids_seen = ids_seen | {id(obj)}
if has_pandas and isinstance(obj, pd.DataFrame):
size = obj.memory_usage(deep=True).sum()
return size, ids_seen
size = sys.getsizeof(obj)
if isinstance(obj, (list, tuple, set, frozenset)):
for item in obj:
item_size, ids_seen = get_real_size(item, ids_seen)
size += item_size
elif isinstance(obj, dict):
for key, value in obj.items():
key_size, ids_seen = get_real_size(key, ids_seen)
value_size, ids_seen = get_real_size(value, ids_seen)
size += key_size + value_size
else:
obj_type = type(obj)
if obj_type not in types_seen:
print(f'Type not handled: {obj_type}')
types_seen.add(obj_type)
return size, ids_seen
def get_memory_usage():
import inspect
# Separate user-defined and system variables
user_vars = {k: v for k, v in globals().items() if not k.startswith('_') and not callable(v) and not inspect.ismodule(v)}
system_vars = {k: v for k, v in globals().items() if k.startswith('_') and not callable(v) and not inspect.ismodule(v)}
ids_seen = frozenset()
memory_usage = {}
for k, v in user_vars.items():
size, ids_seen = get_real_size(v, ids_seen)
memory_usage[k] = size
system_memory = 0
for v in system_vars.values():
size, ids_seen = get_real_size(v, ids_seen)
system_memory += size
# Convert bytes to human-readable format
def sizeof_fmt(num, suffix='B'):
for unit in ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z']:
if abs(num) < 1024.0:
return f"{num:3.1f}{unit}{suffix}"
num /= 1024.0
return f"{num:.1f}Yi{suffix}"
# Format memory usage
memory_usage['_system_vars'] = system_memory
memory_usage_items = sorted(memory_usage.items(), key=lambda x: x[1], reverse=True)
formatted_usage = [(k, sizeof_fmt(v)) for k, v in memory_usage_items]
# Print the sorted list
for var, size in formatted_usage:
print("{:>30}: {:>8}".format(var, size))
# Print totals
print("\nTotal Memory Usage:")
print(f"User Variables: {sizeof_fmt(sum(memory_usage.values()))}")
print(f"System Variables: {sizeof_fmt(system_memory)}")
print(f"Combined Total: {sizeof_fmt(system_memory+sum(memory_usage.values()))}")
get_memory_usage()