HOWTO · Python

在 Python 中确定对象的大小

本教程讨论如何在 Python 中确定对象的大小。

本页内容

使用 sys.getsizeof() 可以获取对象的浅层大小,单位为字节。它不会把该对象所引用对象的大小加总。若要递归估算容器及其内容的大小,可使用 Pympler;若要比较一段时间内 Python 的内存分配情况,则可使用 tracemalloc。

使用 sys.getsizeof() 测量对象的浅层大小

导入 sys,并将要检查的值传给 sys.getsizeof()。返回的整数表示对象浅层大小的字节数。例如,它会计算列表对象本身的大小,但不包括列表中存放的对象。当容器引用了较大的字符串、嵌套容器或其他数据时,这一区别尤其重要。

运行下面的示例来测量内置容器。打印出的字节数是某个环境中的示例读数;它会因 Python 实现和版本而异,并非可移植的固定值:

本节中的代码以及显示的标签或输出仍为英文。

import sys

values = [10, 20, 30]
size_bytes = sys.getsizeof(values)
print(f"Shallow size: {size_bytes} bytes")
Shallow size: 88 bytes

你也可以用同样的方法传入其他值,例如字符串、整数或字典。它们的报告大小同样可能因 Python 实现和版本而异。应将结果视为实现层面的测量值,而不是整个进程内存的保证值,也不能据此推断该值可访问的所有对象所占的总内存。

使用 Pympler 计入被引用的对象

如果需要估算容器可访问的对象所占空间,Pympler 的 asizeof 工具可以递归地计算被引用对象。先使用 pip install pympler 安装第三方包,再从 pympler 导入 asizeof,并将要检查的值传给它。

安装 Pympler 后,运行下面这个独立示例:

本节中的代码以及显示的标签或输出仍为英文。

try:
    from pympler import asizeof
except ImportError:
    print("Install Pympler with: pip install pympler")
else:
    values = [1, 2, [3, 4]]
    print(f"Recursive size: {asizeof.asizeof(values)} bytes")

报告的数值取决于 Python 实现、版本和已安装的 Pympler 版本,因此应将它视为针对该对象图的估算,而不是可移植的固定值。

这种递归估算回答的问题与 sys.getsizeof() 不同:它会计入嵌套对象,而不只计算外层对象的浅层大小。但它仍然只是对象图的估算,并不代表整个 Python 进程、分配器开销或操作系统报告的驻留内存。共享引用和实现细节也会影响递归工具如何计算对象,因此适合用它以一致的方式比较数据结构,不应将结果视为精确的进程内存总量。

使用 tracemalloc 跟踪内存分配

如果要观察程序某一部分运行期间发生的 Python 内存分配,可以使用标准库模块 tracemalloc。在开始关注的操作之前启动跟踪,读取当前和峰值跟踪内存的大小(单位为字节),完成后停止跟踪。下面的独立示例会在跟踪期间分配一个列表,并报告这两个读数;显示的数值是某个环境中的示例读数,会因 Python 实现和运行环境而异。

本节中的代码以及显示的标签或输出仍为英文。

import tracemalloc

tracemalloc.start()
values = [number for number in range(1000)]
current_bytes, peak_bytes = tracemalloc.get_traced_memory()
print(f"Current traced memory: {current_bytes} bytes")
print(f"Peak traced memory: {peak_bytes} bytes")
tracemalloc.stop()
Current traced memory: 29536 bytes
Peak traced memory: 29536 bytes

current_bytes 表示当前跟踪到的内存量,peak_bytes 表示自开始跟踪以来记录到的最高内存量。必须在分配发生前启动跟踪,才能记录该分配;这些读数反映的是被跟踪的 Python 内存分配,而不是某个指定对象递归保留的总大小。调查内存分配发生位置时,可以使用快照,或在有意义的时间点比较读数。测量完成后停止跟踪,避免不必要地继续收集数据。