sys.getsizeof仅返回对象自身开销,不递归计算嵌套引用;测量容器时忽略元素内存,需用pympler.asizeof或手动递归(注意循环/重复引用)才接近真实占用。

sys.getsizeof只返回对象自身开销,不递归计算嵌套引用
sys.getsizeof 对 list、dict、tuple 等容器类型,只返回其内部指针数组和元数据的内存(通常 56–112 字节),完全不包含它所引用的元素对象。比如一个含 1000 个 int 的列表,sys.getsizeof 返回值几乎恒定,和元素数量无关。
常见错误现象:用 sys.getsizeof 测量 data = [[i] * 100 for i in range(1000)],结果只有 ~8000 字节,远低于真实占用(实际超 8MB)。
原因在于 Python 对象内存由两部分组成:对象头 + 实际数据;而容器只“持有引用”,sys.getsizeof 不追踪这些引用目标。
手动递归计算需处理循环引用和重复引用
要逼近真实内存,得自己遍历对象图,但必须避免无限递归或重复计数。标准做法是用 id() 记录已访问对象地址,跳过已见对象:
import sys
from collections import deque
<p>def get_deep_size(obj, seen=None):
if seen is None:
seen = set()
obj_id = id(obj)
if obj_id in seen:
return 0
seen.add(obj_id)</p><pre class="brush:python;toolbar:false;">size = sys.getsizeof(obj)
if isinstance(obj, (list, tuple, set, frozenset, deque)):
size += sum(get_deep_size(item, seen) for item in obj)
elif isinstance(obj, dict):
size += sum(get_deep_size(k, seen) + get_deep_size(v, seen) for k, v in obj.items())
elif hasattr(obj, '__dict__'):
size += get_deep_size(obj.__dict__, seen)
elif hasattr(obj, '__slots__'):
for slot in obj.__slots__:
if hasattr(obj, slot):
size += get_deep_size(getattr(obj, slot), seen)
return size
注意点:
- 该函数仍无法计入 C 扩展对象(如
numpy.ndarray)内部缓冲区,需单独适配 - 对字符串、小整数、短元组等共享对象(interned / singleton),
id()去重会低估——这是 Python 内存模型决定的,非 bug -
__slots__类需显式检查,否则字段被忽略
更可靠的选择:用 pympler.getsizeof 替代手写逻辑
pympler 的 asizeof.asizeof 是目前最健壮的通用方案,它内置了对常见内置类型、numpy、pandas、自定义类的支持,并自动处理循环/重复引用。
安装与使用:
pip install pympler
from pympler import asizeof size = asizeof.asizeof(your_nested_obj)
关键优势:
- 默认启用
detail=True可返回各子对象大小分布(调试用) - 支持
limit=1000防止深度过大卡死 - 对
__weakref__、__dict__、__slots__全覆盖,无需手动分支 - 比手写递归快 2–5 倍(Cython 加速)
但它仍不是“绝对真实”——Python 解释器底层内存池、对齐填充、GC 预留空间等不可见层,任何用户态工具都测不到。
测量前务必禁用 gc 并考虑对象生命周期
GC 会延迟回收,导致 asizeof 或手写函数把已“逻辑删除”但未回收的对象算进去。实操时应:
- 调用
import gc; gc.collect()清理后再测 - 避免在交互式环境(如 IPython/Jupyter)中直接测变量——临时变量可能被
_引用残留 - 对大对象,用
del obj后再gc.collect(),确认无外部引用 - 若对象含
__del__方法,GC 可能推迟清理,此时测量值偏高且不稳定
真正难的是区分“谁该为这块内存负责”——比如一个 list 和它里面的 str,如果多个容器共享同一 str,按所有权归属分配内存就涉及业务语义,工具只能给总量。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











