别再瞎优化了!Python 内存泄漏 10 大经典案例 + 工具脚本,建议收藏

张开发
2026/4/13 4:01:21 15 分钟阅读

分享文章

别再瞎优化了!Python 内存泄漏 10 大经典案例 + 工具脚本,建议收藏
引言你是不是也遇到过这些崩溃现场Python 服务跑几天就 OOM 被系统杀死只能无奈重启内存曲线一路飙升GC 执行无数次也不回落接口越来越慢CPU 忽高忽低日志却毫无异常线上排查一夜最后还是不知道哪里泄漏很多人把锅甩给 “Python 垃圾回收不行”但真相是99% 的内存泄漏都是代码引用没释放跟 GC 半毛钱关系没有本文不讲虚的理论全程可运行代码 真实案例 工具脚本带你吃透内存泄漏成因、10 类经典泄漏代码、定位工具、生产级修复方案。建议点赞 收藏 关注这篇文章足够你解决 80% 线上内存问题一、先搞懂Python 内存为什么会 “漏”1.1 Python 内存管理机制一句话讲透引用计数对象没人用了计数为 0 直接销毁分代回收专门解决循环引用问题内存泄漏对象明明不用了却还被人 “抓着不放”GC 想回收都收不回1.2 如何一眼判断是不是泄漏正常内存有升有降GC 后明显回落泄漏内存只涨不跌GC 完全无效严重泄漏对象数量疯狂增长最终 OOM 崩溃二、10 类经典内存泄漏全是生产踩坑代码下面这些代码你项目里 100% 出现过2.1 全局列表无限追加最常见泄漏 NO.1python运行# 全局列表永不清理内存直接拉满 request_log [] def handle_request(user_id): data {user_id: user_id, content: big_data * 1024} request_log.append(data) # 无限增长 if __name__ __main__: for i in range(1000): handle_request(i)坑点全局变量是 GC 根对象永远不会被回收。2.2 类静态变量持有实例python运行class User: user_pool [] # 类变量进程生命周期 def __init__(self, uid): self.uid uid User.user_pool.append(self) # 实例永远被静态列表持有 for i in range(2000): User(i)2.3 闭包缓存无限膨胀python运行def make_counter(): cache {} def counter(key): cache[key] cache.get(key, 0) 1 return counter cnt make_counter() # key 越来越多cache 永远不清 for i in range(10000): cnt(fuser_{i})2.4 无上限装饰器缓存致命坑python运行def my_cache(func): storage {} def wrapper(*args): storage[args] func(*args) return storage[args] return wrapper my_cache def calc(x): return x * 2 # 跑一会儿内存直接爆炸 for i in range(50000): calc(i)2.5 循环引用 del导致无法回收python运行class Node: def __init__(self): self.other None # 有 __del__GC 直接摆烂 def __del__(self): pass a, b Node(), Node() a.other b b.other a # 永远变成垃圾无法回收2.6 文件句柄未关闭系统级崩溃python运行def read_file(): f open(large_file.txt) # 没 close return f.read() # 循环一开直接 Too many open files for _ in range(1000): read_file()2.7 数据库连接不归还python运行import sqlite3 def query(): conn sqlite3.connect(:memory:) cursor conn.cursor() # 不关闭、不归还连接池 return cursor.execute(select 1) for _ in range(2000): query()2.8 日志上下文无限缓存python运行class LogContext: logs [] classmethod def add(cls, msg): cls.logs.append({msg: msg, data: x*1024*200}) for i in range(300): LogContext.add(freq_{i})2.9 异步任务全局持有不清理python运行import asyncio task_list [] async def job(): big_data [0]*100000 await asyncio.sleep(3600) async def main(): for _ in range(200): t asyncio.create_task(job()) task_list.append(t) # 永久持有 asyncio.run(main())2.10 第三方库隐性泄漏requests/pandaspython运行import requests def fetch(): # 连接池、响应体隐性持有引用 return requests.get(https://httpbin.org/get) for _ in range(1000): fetch()三、内存排查神器4 个工具直接定位代码行不用瞎猜工具一跑泄漏位置直接给你标出来3.1 psutil快速看内存涨不涨python运行import psutil, os def rss(): return f{psutil.Process(os.getpid()).memory_info().rss/1024/1024:.2f}MB print(rss())3.2 tracemallocPython 内置神器强烈推荐直接告诉你哪一行代码、分配了多少内存python运行import tracemalloc tracemalloc.start(20) s1 tracemalloc.take_snapshot() # 运行你的泄漏代码 s2 tracemalloc.take_snapshot() for stat in s2.compare_to(s1, lineno)[:10]: print(stat)3.3 memory_profiler逐行看内存变化python运行from memory_profiler import profile profile def test(): arr [] for i in range(10000): arr.append({id:i}) test()3.4 objgraph看谁在抓着对象不放python运行import objgraph objgraph.show_growth(limit5) # 查看引用链直接生成图片 objs objgraph.by_type(dict) objgraph.show_backrefs(objs[0], max_depth3)四、真实实战从泄漏 → 定位 → 修复全流程场景Flask 服务内存疯涨7 天 OOM步骤 1定位泄漏代码python运行log_list [] def process(req): log_list.append({req: req, data: a*1024*500})步骤 2工具定位tracemalloc 直接指向log_list.append(...)步骤 3修复三种方案任选python运行# 方案1限制长度推荐 from collections import deque log_list deque(maxlen200) # 方案2定时清理 if len(log_list) 200: del log_list[:100] # 方案3弱引用 import weakref log_list []步骤 4验证内存稳定、对象不再增长、GC 有效回收。五、生产级根治方案直接抄5.1 代码规范禁止全局列表无限 append缓存必须加maxsize/ TTL一律用with关闭资源大对象用完del或 None少写__del__方法5.2 数据结构优化deque(maxlen)代替 listlru_cache(maxsize128)生成器(x for x in ...)代替列表数值用array.array5.3 线上防护内存 RSS 告警GC 频率监控定时自动清理极端情况定时重启六、高频问题面试 排查必备Q1GC 了内存为什么不降因为对象被GC Root持有全局变量、类变量、闭包、协程、模块对象。Q2循环引用一定泄漏吗不一定只有被根对象引用 __del__才会真泄漏。Q3生产能开 profiling 吗推荐tracemalloc、gc、py-spy低开销不推荐memory_profiler耗性能Q4最快判断泄漏方法python运行import gc print(内存) gc.collect() print(内存) # 不回落 泄漏结尾本文覆盖了 Python 内存泄漏10 大经典场景 4 大定位工具 完整实战代码全部可直接复制运行遇到线上内存问题直接对照排查。如果这篇文章对你有用欢迎点赞、收藏、关注后续会持续更新Python 性能优化、GIL 详解、虚拟机底层原理、高并发实战等硬核干货。你在项目中遇到过哪些奇葩内存泄漏欢迎在评论区留言我会一一回复解答

更多文章