tracemalloc - Trace memory allocations - 跟踪内存分配

tracemalloc是Python内置的内存追踪模块,能详细记录内存分配情况,帮助开发者定位内存泄漏。它提供了分配对象的回溯、每个文件和每行分配的内存块的统计信息以及计算两个快照之间的差异等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

tracemalloc - Trace memory allocations - 跟踪内存分配

tracemalloc - 跟踪内存分配
https://docs.python.org/zh-cn/3.8/library/tracemalloc.html

tracemalloc - Trace memory allocations
https://docs.python.org/3.8/library/tracemalloc.html

Source code: Lib/tracemalloc.py

The tracemalloc module is a debug tool to trace memory blocks allocated by Python. It provides the following information:
tracemalloc 模块是一个调试工具,用于跟踪 Python 分配的内存块。它提供以下信息:

  • Traceback where an object was allocated - 分配对象的回溯
  • Statistics on allocated memory blocks per filename and per line number: total size, number and average size of allocated memory blocks - 每个文件和每行分配的内存块的统计信息:分配的内存块的总大小、数量和平均大小
  • Compute the differences between two snapshots to detect memory leaks - 计算两个快照之间的差异以检测内存泄漏
traceback:n. 回溯

To trace most memory blocks allocated by Python, the module should be started as early as possible by setting the PYTHONTRACEMALLOC environment variable to 1, or by using -X tracemalloc command line option. The tracemalloc.start() function can be called at runtime to start tracing Python memory allocations.
跟踪由 Python 分配的大多数内存块,应通过将环境变量 PYTHONTRACEMALLOC 设置为 1 或使用 -X tracemalloc 命令行选项来尽早启动该模块。可以在运行时调用 tracemalloc.start() 函数来开始跟踪 Python 内存分配。

By default, a trace of an allocated memory block only stores the most recent frame (1 frame). To store 25 frames at startup: set the PYTHONTRACEMALLOC environment variable to 25, or use the -X tracemalloc=25 command line option.
默认情况下,分配的存储块的跟踪仅存储最近的帧 (1 frame)。要在启动时存储 25 帧,请执行以下操作:将环境变量 PYTHONTRACEMALLOC 设置为 25,或使用 -X tracemalloc=25 命令行选项。

1. Display the top 10

Display the 10 files allocating the most memory:

import tracemalloc

tracemalloc.start()

# ... run your application ...

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

print("[ Top 10 ]")
for stat in top_stats[:10]:
    print(stat)

Example of output of the Python test suite:

[ Top 10 ]
<frozen importlib._bootstrap>:716: size=4855 KiB, count=39328, average=126 B
<frozen importlib._bootstrap>:284: size=521 KiB, count=3199, average=167 B
/usr/lib/python3.4/collections/__init__.py:368: size=244 KiB, count=2315, average=108 B
/usr/lib/python3.4/unittest/case.py:381: size=185 KiB, count=779, average=243 B
/usr/lib/python3.4/unittest/case.py:402: size=154 KiB, count=378, average=416 B
/usr/lib/python3.4/abc.py:133: size=88.7 KiB, count=347, average=262 B
<frozen importlib._bootstrap>:1446: size=70.4 KiB, count=911, average=79 B
<frozen importlib._bootstrap>:1454: size=52.0 KiB, count=25, average=2131 B
<string>:5: size=49.7 KiB, count=148, average=344 B
/usr/lib/python3.4/sysconfig.py:411: size=48.0 KiB, count=1, average=48.0 KiB

We can see that Python loaded 4855 KiB data (bytecode and constants) from modules and that the collections module allocated 244 KiB to build namedtuple types.
我们可以看到 Python 从模块中加载了 4855 KiB 数据 (字节码和常量),并且 collections 模块分配了 244 KiB 来构建 namedtuple 类型。

2. Compute differences

Take two snapshots and display the differences:

import tracemalloc
tracemalloc.start()
# ... start your application ...

snapshot1 = tracemalloc.take_snapshot()
# ... call the function leaking memory ...
snapshot2 = tracemalloc.take_snapshot()

top_stats = snapshot2.compare_to(snapshot1, 'lineno')

print("[ Top 10 differences ]")
for stat in top_stats[:10]:
    print(stat)

Example of output before/after running some tests of the Python test suite:

[ Top 10 differences ]
<frozen importlib._bootstrap>:716: size=8173 KiB (+4428 KiB), count=71332 (+39369), average=117 B
/usr/lib/python3.4/linecache.py:127: size=940 KiB (+940 KiB), count=8106 (+8106), average=119 B
/usr/lib/python3.4/unittest/case.py:571: size=298 KiB (+298 KiB), count=589 (+589), average=519 B
<frozen importlib._bootstrap>:284: size=1005 KiB (+166 KiB), count=7423 (+1526), average=139 B
/usr/lib/python3.4/mimetypes.py:217: size=112 KiB (+112 KiB), count=1334 (+1334), average=86 B
/usr/lib/python3.4/http/server.py:848: size=96.0 KiB (+96.0 KiB), count=1 (+1), average=96.0 KiB
/usr/lib/python3.4/inspect.py:1465: size=83.5 KiB (+83.5 KiB), count=109 (+109), average=784 B
/usr/lib/python3.4/unittest/mock.py:491: size=77.7 KiB (+77.7 KiB), count=143 (+143), average=557 B
/usr/lib/python3.4/urllib/parse.py:476: size=71.8 KiB (+71.8 KiB), count=969 (+969), average=76 B
/usr/lib/python3.4/contextlib.py:38: size=67.2 KiB (+67.2 KiB), count=126 (+126), average=546 B

We can see that Python has loaded 8173 KiB of module data (bytecode and constants), and that this is 4428 KiB more than had been loaded before the tests, when the previous snapshot was taken. Similarly, the linecache module has cached 940 KiB of Python source code to format tracebacks, all of it since the previous snapshot.
我们可以看到 Python 已经加载了 8173 KiB 的模块数据 (字节码和常量),这比在获取前一个快照时 (在测试之前) 加载的数据多了 4428 KiB。类似地,linecache 模块已经缓存了 940 KiB 的 Python 源代码以格式化回溯,所有这些都是自上次快照以来的。

If the system has little free memory, snapshots can be written on disk using the Snapshot.dump() method to analyze the snapshot offline. Then use the Snapshot.load() method reload the snapshot.
如果系统的可用内存很少,则可以使用 Snapshot.dump() 方法将快照写入磁盘,以离线分析快照。然后使用 Snapshot.load() 方法重新加载快照。

3. Get the traceback of a memory block

Code to display the traceback of the biggest memory block (显示最大内存块的回溯代码):

import tracemalloc

# Store 25 frames
tracemalloc.start(25)

# ... run your application ...

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('traceback')

# pick the biggest memory block
stat = top_stats[0]
print("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))
for line in stat.traceback.format():
    print(line)

Example of output of the Python test suite (traceback limited to 25 frames):

903 memory blocks: 870.1 KiB
  File "<frozen importlib._bootstrap>", line 716
  File "<frozen importlib._bootstrap>", line 1036
  File "<frozen importlib._bootstrap>", line 934
  File "<frozen importlib._bootstrap>", line 1068
  File "<frozen importlib._bootstrap>", line 619
  File "<frozen importlib._bootstrap>", line 1581
  File "<frozen importlib._bootstrap>", line 1614
  File "/usr/lib/python3.4/doctest.py", line 101
    import pdb
  File "<frozen importlib._bootstrap>", line 284
  File "<frozen importlib._bootstrap>", line 938
  File "<frozen importlib._bootstrap>", line 1068
  File "<frozen importlib._bootstrap>", line 619
  File "<frozen importlib._bootstrap>", line 1581
  File "<frozen importlib._bootstrap>", line 1614
  File "/usr/lib/python3.4/test/support/__init__.py", line 1728
    import doctest
  File "/usr/lib/python3.4/test/test_pickletools.py", line 21
    support.run_doctest(pickletools)
  File "/usr/lib/python3.4/test/regrtest.py", line 1276
    test_runner()
  File "/usr/lib/python3.4/test/regrtest.py", line 976
    display_failure=not verbose)
  File "/usr/lib/python3.4/test/regrtest.py", line 761
    match_tests=ns.match_tests)
  File "/usr/lib/python3.4/test/regrtest.py", line 1563
    main()
  File "/usr/lib/python3.4/test/__main__.py", line 3
    regrtest.main_in_temp_cwd()
  File "/usr/lib/python3.4/runpy.py", line 73
    exec(code, run_globals)
  File "/usr/lib/python3.4/runpy.py", line 160
    "__main__", fname, loader, pkg_name)

We can see that the most memory was allocated in the importlib module to load data (bytecode and constants) from modules: 870.1 KiB. The traceback is where the importlib loaded data most recently: on the import pdb line of the doctest module. The traceback may change if a new module is loaded.
我们可以看到,在 importlib 模块中分配了最多的内存,以从模块中加载数据 (字节码和常量):870.1 KiB。回溯是 importlib 最近加载数据的位置:在 doctest 模块的 import pdb 行上。如果加载了新模块,则回溯可能会更改。

4. Functions

tracemalloc.clear_traces()
Clear traces of memory blocks allocated by Python.
清除由 Python 分配的内存块的痕迹。

tracemalloc.stop()
Stop tracing Python memory allocations: uninstall hooks on Python memory allocators. Also clears all previously collected traces of memory blocks allocated by Python.
停止跟踪 Python 内存分配:卸载 Python 内存分配器上的钩子。同时清除由 Python 分配的所有先前收集的内存块跟踪。

Call take_snapshot() function to take a snapshot of traces before clearing them.
调用 take_snapshot() 函数在清除痕迹之前对其进行快照。

statistics(key_type: str, cumulative: bool=False)
获取 Statistic 信息列表,按 key_type 分组排序:

在这里插入图片描述

If cumulative is True, cumulate size and count of memory blocks of all frames of the traceback of a trace, not only the most recent frame. The cumulative mode can only be used with key_type equals to filename and lineno.
如果 cumulative 为 True,则累计跟踪回溯所有帧的大小和存储块数,而不仅仅是最近的帧。累积模式只能与 key_type 等于 filename and lineno 时一起使用。

The result is sorted from the biggest to the smallest by: Statistic.size, Statistic.count and then by Statistic.traceback.
结果按从大到小排序:Statistic.size, Statistic.count,然后按 Statistic.traceback。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值