sys.getsizeof()仅返回容器自身外壳大小,不包含元素内存;pympler.asizeof()递归计算全部引用对象并自动去重,结果更真实;NumPy/Pandas需用专用接口如nbytes或memory_usage(deep=True)。

sys.getsizeof() 对 dict/list 等容器完全不适用
它只返回“外壳”大小,比如一个含 1000 个字符串的 dict,sys.getsizeof() 可能只报 216 字节,而真实占用可能超几 MB。原因在于:它不递归进入 value、不处理字符串驻留(id("a") == id("a"))、不跳过重复引用、也不统计小整数缓存(-5~256)这类共享对象。对 list、tuple、自定义类实例同理——你看到的只是指针数组或 __dict__ 的浅层开销。
pympler.asizeof() 是最省心的真实值替代方案
asizeof() 会自动递归遍历所有引用对象,内部已做去重(跳过相同 id())、绕过内置类型(如 type、function),并兼容 __slots__、弱引用表等细节。安装后直接用:
from pympler import asizeof
data = {"users": [{"name": "Alice", "scores": [95, 87, 91]} for _ in range(1000)]}
print(asizeof.asizeof(data)) # 输出真实字节数,通常比 sys.getsizeof() 高 1–2 个数量级- 无需手动写递归逻辑,避免无限循环或重复计数
- 对
numpy.ndarray、pandas.DataFrame仍不适用——这些得走专用接口 - 性能比手写递归略慢,但结果更可靠;适合调试、压测、上线前内存审计
NumPy/Pandas 必须绕过 sys.getsizeof(),改用原生接口
它们的内存主体在 C 堆上,sys.getsizeof() 返回的只是 Python 包装器(几十到几百字节),毫无参考价值。
-
numpy.ndarray:用arr.nbytes(不含 dtype 元数据开销)或arr.__array_interface__['data'][0]查底层地址(极少需要) -
pandas.Series/DataFrame:必须用df.memory_usage(deep=True).sum(),其中deep=True才计入object列中字符串的实际内容 - 混合结构(如 DataFrame 里存了 list 或 dict):
memory_usage(deep=True)仍不够,需单独对 object 列调用asizeof.asizeof()
tracemalloc 更适合定位“谁在分配”,而非“对象占多少”
如果你的问题是“为什么内存涨了 500MB”,而不是“这个 dict 到底多大”,tracemalloc 才是正解。它记录的是运行时实际申请的内存块,能精确到行号和文件:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
立即学习“Python免费学习笔记(深入)”;
import tracemalloc
tracemalloc.start()
# ... 运行可疑代码段 ...
snapshot = tracemalloc.take_snapshot()
for stat in snapshot.statistics('lineno')[:5]:
print(stat)注意:tracemalloc 不反映对象当前总驻留内存(比如被缓存但未释放的对象),也不处理 C 扩展分配(如 numpy 底层 malloc)。它只告诉你“哪行代码新申请了最多内存”。
真实内存测量最易被忽略的一点:没有银弹。asizeof() 对纯 Python 结构最准,但遇到 ctypes、array.array、自定义 C 扩展或 mmap 文件,依然会漏掉底层 buffer。这种场景下,得结合 /proc/[pid]/smaps(Linux)或系统级工具交叉验证。

















