🧠 图解记忆:AI 应用的 OOM 四大场景;点击图片可查看原图。
💡 答案要点
AI 应用的 OOM 四大场景:
1. 大模型加载:模型太大,显存不够
2. Batch 处理:批量请求堆积,内存暴涨
3. 向量数据库:大规模向量撑爆 RAM
4. 异步任务:并发任务未释放,内存泄漏诊断工具:
| 工具 | 用途 | 典型用法 |
|---|---|---|
tracemalloc | 定位内存分配 | 对比快照,找泄漏点 |
objgraph | 对象引用链 | 查谁持有对象不释放 |
memory_profiler | 行级内存占用 | @profile 装饰器 |
psutil | 进程内存监控 | 实时告警 |
gdb | 显存问题 | CUDA OOM 调试 |
实战:tracemalloc 排查内存泄漏:
python
import tracemalloc
import gc
# 启动追踪
tracemalloc.start()
# ... 执行你的代码 ...
# 抓取快照
snapshot1 = tracemalloc.take_snapshot()
# 执行可疑代码(N 次循环)
for _ in range(100):
# 模拟:每次创建大对象但不释放
data = [list(range(10000)) for _ in range(100)]
# 正确做法:del data 或在循环内创建
gc.collect() # 强制垃圾回收
snapshot2 = tracemalloc.take_snapshot()
# 对比快照
top_stats = snapshot2.compare_to(snapshot1, 'lineno')
print("内存增长 Top 10:")
for stat in top_stats[:10]:
print(stat)常见泄漏模式 + 修复:
展开 Python 代码示例(49 行)
python
# 泄漏模式 1:全局列表不断追加
class MemoryLeakyCache:
"""有内存泄漏的缓存"""
def __init__(self):
self.history = [] # ❌ 不断追加,永不清理
def add(self, key, value):
self.history.append((key, value)) # 内存持续增长
return value
# 修复:LRU 缓存或固定大小
from functools import lru_cache
@lru_cache(maxsize=1000)
def cached_result(query: str) -> str:
"""自动 LRU 清理"""
return expensive_computation(query)
# 泄漏模式 2:未关闭的流式响应
async def leaky_stream():
async for chunk in llm.stream():
process(chunk)
# ❌ 如果中途异常,response 未关闭
# 修复:async with 或 try/finally
async def fixed_stream():
async with llm.stream() as response:
async for chunk in response:
process(chunk)
# ✅ 无论是否异常都会清理
# 泄漏模式 3:大对象序列化残留
def leaky_json_processing():
data = load_large_json("big_file.json") # 加载大 JSON
result = json.dumps(data) # 序列化
# ❌ data 还在内存中
del data # 需要手动删除
return result
# 修复:流式 JSON 解析
import ijson
def fixed_streaming_json():
with open("big_file.json", "rb") as f:
for item in ijson.items(f, "item"): # 流式解析
process(item)AI 应用专项:大模型显存管理:
展开 Python 代码示例(39 行)
python
# 场景:多模型部署,显存不够
import torch
def load_model_memory_efficient(model_name: str):
"""显存高效加载"""
if torch.cuda.is_available():
# 1. 量化加载(INT8/INT4)
model = AutoModelForCausalLM.from_pretrained(
model_name,
torch_dtype=torch.float16, # FP16 加载
load_in_8bit=True, # INT8 量化(bitsandbytes)
device_map="auto", # 自动分配到多卡
)
# 2. 梯度检查点(减少显存)
model.gradient_checkpointing_enable()
# 3. 使用 Python 垃圾回收
import gc
gc.collect()
torch.cuda.empty_cache() # 清理未使用的缓存
return model
# 监控显存
def monitor_gpu_memory():
"""每 N 秒监控一次显存"""
import time
while True:
if torch.cuda.is_available():
allocated = torch.cuda.memory_allocated() / 1024**3 # GB
reserved = torch.cuda.memory_reserved() / 1024**3
print(f"Allocated: {allocated:.2f}GB, Reserved: {reserved:.2f}GB")
# OOM 预警
if allocated > 0.9 * torch.cuda.get_device_properties(0).total_memory / 1024**3:
print("⚠️ 显存使用率 > 90%,即将 OOM")
time.sleep(30)面试话术:
"AI 应用的 OOM 有四种常见原因:大模型加载(用 FP16/INT8 量化)、Batch 堆积(加 Semaphore 限流)、向量库太大(用内存映射或分片)、异步任务泄漏(用 async with 确保清理)。排查用 tracemalloc 对比快照,核心是'谁持有了对象不释放'。我做生产级 AI 服务有个习惯:加 psutil 实时监控内存,超过 80% 自动告警,超过 90% 自动触发 GC,不等到 OOM 才处理。"
