---
title: "Python 进程内存持续上升：用 tracemalloc 定位仍存活的分配"
date: 2026-11-13
slug: python-tracemalloc-retained-allocations
canonical: https://kernelranch.com/blog/2026/11/python-tracemalloc-retained-allocations
markdown_url: https://kernelranch.com/blog/2026/11/python-tracemalloc-retained-allocations.md
tags: ["python", "memory", "profiling"]
---相同批次反复处理后，进程占用一直变大。先在安静点抓两张 Python 分配快照，按行号看哪些分配一直存在。再清理可疑持有者，第三张快照用来验证这些对象是否消失。

## 1. 只比较一个已经知道的分配位置

保存为 memory_lab.py，运行 python memory_lab.py。

```python
import gc
import tracemalloc

def fill(cache):
    for key in range(40):
        cache[key] = bytearray(128 * 1024)  # tracked allocation

def measured_growth(before, after, line):
    return sum(
        stat.size_diff for stat in after.compare_to(before, "lineno")
        if stat.traceback[0].filename == __file__ and stat.traceback[0].lineno == line
    )

line = fill.__code__.co_firstlineno + 2
cache = {}
tracemalloc.start()
try:
    before = tracemalloc.take_snapshot()
    fill(cache)
    # This temporary allocation has ended before the snapshot.
    temporary = bytearray(1024 * 1024)
    del temporary
    retained = tracemalloc.take_snapshot()
    growth = measured_growth(before, retained, line)
    assert growth >= 5 * 1024 * 1024
    print("retained payload: at least 5 MiB")

    cache.clear()
    gc.collect()
    after = tracemalloc.take_snapshot()
    assert measured_growth(before, after, line) == 0
    print("after clearing cache: allocation line back to baseline")
finally:
    tracemalloc.stop()
```

本机实测输出如下。

```text
retained payload: at least 5 MiB
after clearing cache: allocation line back to baseline
```

## 2. 在真实负载里缩小范围

真实排查时先按 lineno 排序看正增长，再按 traceback 聚合追到调用入口。对照快照应在相近负载、相同并发和同一业务阶段采集。例如每批队列排空后采样，避免把不同数量的进行中请求误判为泄漏。

| 观察结果 | 下一步 |
|---|---|
| 固定分配行在多批次后持续净增长 | 检查缓存、队列或全局对象如何保留引用 |
| 清理引用后快照下降，进程 RSS 仍高 | 检查分配器复用及操作系统内存指标 |
| RSS 上升，Python 快照几乎不变 | 调查本机扩展、映射文件或其他分配来源 |

tracemalloc 给出分配位置。要确认谁持有引用，需要结合缓存条目数、对象生命周期和应用代码。启用追踪有开销，可以先在复现场景启用，提前开始采集以免漏掉基线。

## 小结

用同一批次边界采样，找出仍存活的分配，再通过释放引用后的快照验证原因。

## 数据来源与检索时间

检索时间 2026-11-13。

| 来源 | URL | 对应内容 |
|---|---|---|
| Python tracemalloc | https://docs.python.org/3.11/library/tracemalloc.html | 快照比较、行号和追踪范围 |

## 核验说明

- Python 3.11.9 验证保留的 bytearray 和清理后的快照。实验未用 RSS 推算 Python 对象大小。
