Uvicorn本身极少导致OOM,内存持续上涨95%源于应用逻辑泄漏:如GPU推理显存未控、def函数误入线程池致对象堆积、on_startup未配on_shutdown清理、多worker引发显存翻倍等。

Uvicorn 本身几乎不会导致内存溢出(OOM),它只是 ASGI 服务器,不持有业务对象。你看到的 MemoryError 或进程被 OOM Killer 杀掉,95% 是你的应用逻辑或依赖库在吃内存——尤其是 GPU 推理、大文件处理、同步函数误入线程池、未释放的缓存/连接等场景。
为什么 Uvicorn 进程 RSS 持续上涨但没立刻 OOM
这是典型的“缓慢泄漏”,不是瞬间爆掉。Uvicorn 的 --workers 模式下每个子进程独立运行,若某个 worker 的 VmRSS 稳定上升而线程数不变,说明堆内存里有对象没被回收:
- 用
ps aux --sort=-%mem | head -10找出高内存 worker PID - 执行
cat /proc/,确认是堆增长而非线程爆炸/status | grep -E 'VmRSS|Threads' - 临时改单 worker 启动:
uvicorn main:app --workers 1 --loop asyncio,如果涨速明显下降,优先排查 uvloop 兼容性或 worker 隔离失效 - 检查是否在
on_startup里注册了全局缓存、数据库连接池、模型实例,却没配on_shutdown清理
FastAPI 路由里 def 同步函数引发的隐式线程池堆积
这是最常被忽略的泄漏源。Uvicorn 把 def 函数扔进默认 ThreadPoolExecutor,而线程复用 + 闭包引用会让大对象(如 torch.Tensor、dict 缓存)长期驻留:
Uvicorn 0.52.1 是 Python ASGI Web 服务器,提供异步应用服务及 WebSocket 支持,常用于 FastAPI、Starlette 等应用的开发和部署。本下载为官方 PyPI 通用 wheel 包,可使用 pip 安装,并由包管理器处理所需依赖。
- 现象:内存随请求数线性上涨,单次请求返回后不回落;
objgraph.show_most_common_types()显示大量weakref、_thread._local - 修复:所有路径函数统一改用
async def;若必须用def(如调用阻塞库),确保内部不构造大对象,并用try/finally显式释放资源 - 不要依赖线程退出自动清理——Python 线程池不会清空
threading.local变量
CUDA 显存 OOM 不是 Uvicorn 错,但它的启动方式会放大问题
显存溢出常被误认为内存溢出,但本质不同:CUDA out of memory 是 GPU 显存耗尽,和 Python 进程 RSS 无关。Uvicorn 的 --workers 参数在这里是关键陷阱:
- 每个 worker 是独立进程,各自初始化 CUDA context(固定占几百 MB~1GB),并各自加载一份模型权重
- 4 个 worker + 7B FP16 模型 → 光权重就吃掉 4 × 14GB = 56GB 显存,远超单卡容量
- 解决方案:禁用多 worker,改用单进程 + 并发控制(如
threading.BoundedSemaphore或asyncio.Semaphore),并在推理前调用torch.cuda.empty_cache() - 额外注意:PyTorch 的 CUDA caching allocator 会导致显存碎片,
nvidia-smi看似还有余量,但分配不出连续块
真正难处理的从来不是“怎么加内存”,而是“哪个对象在偷偷占着不放”。查泄漏要分层:先确认是 CPU 内存还是 GPU 显存,再锁定是进程级泄漏(worker 隔离失败)、线程级泄漏(ThreadPoolExecutor 复用)、还是 GPU 级泄漏(KV cache 积累、未释放张量)。别一上来就调 --workers 或 --limit-memory,那些参数对根本原因毫无作用。










