
Memory Leak investigation
快速结论:在重复调用 model.transcribe() 处理短音频时,系统内存(RAM)会持续增长,最终导致进程被 OOM Killer 终止。优先排查音频解码阶段的内存泄漏,尝试在每次转写后手动触发垃圾回收,或复用 faster_whisper.decode_audio() 输出。
问题场景
用户在使用 Faster Whisper(模型为 small,设备为 CUDA)进行批量音频转写时,以循环方式反复调用 model.transcribe(),每次处理约 4.5 MB 的 9 分钟音频文件。持续数小时后,系统内存(RAM)被占满,SageMaker 或 EC2 实例上的 Worker 进程被 SIGKILL 杀死。问题在 AWS SageMaker 和 EC2(ml.g4dn.xlarge,CUDA 11,Python 3.10)上均被复现。
报错原文
[ERROR] Worker (pid:25) was sent SIGKILL! Perhaps out of memory?
以及在内存监控中观察到的持续增长:
Baseline
1430.97856
1431.109632
...
1574.223872
1594.605568
...
1630.000000 (示例增长趋势,单位 MB)
原因分析
可能原因:音频解码(audio decoding)阶段存在内存泄漏。Issue 维护者通过实验发现:在每次调用 model.transcribe() 时,如果每次都传入原始音频文件路径,内存使用会逐步上升;但如果预先将音频解码一次(使用 faster_whisper.decode_audio()),然后将解码后的数据重复传入 model.transcribe(),内存则保持平坦,不再增长。此外,强制在每次转写后运行 gc.collect() 也能抑制内存增长,说明部分内存未及时被 Python 垃圾回收器回收。
环境排查
- 确认 Python 版本:Python 3.10(已知环境)
- 确认 CUDA 版本:CUDA 11(已知环境)
- 确认 faster-whisper 版本:建议检查是否为最新版,或参考 Issue 中对应版本
- 确认是否使用 GPU 设备:device=”cuda” 或 device=”CUDA”(大小写敏感,建议统一为小写 “cuda”)
- 确认系统内存(RAM)大小:例如示例中 16 GB,观察基线内存约 1.4 GB
- 可选:安装
psutil库用于监控进程内存
解决步骤
- 手动触发垃圾回收(可优先尝试):在每次
model.transcribe()调用后,显式调用gc.collect()。实测可稳定内存占用。 - 复用解码后的音频数据(推荐):对于重复转写相同音频文件的场景,预先使用
faster_whisper.decode_audio()解码一次,然后将解码后的数组传入model.transcribe()的audio参数,避免每次重新解码。 - 检查 GPU 内存使用(仅涉及 GPU 内存增长的附加场景):如果使用 Large V2 模型及 float16 量化,注意 GPU 内存可能存在峰值,必要时减少同时并发的模型加载数量或降低精度(如使用 int8 量化)。
示例代码调整(结合两种方案):
import gc
import faster_whisper
model = faster_whisper.WhisperModel("small", device="cuda")
# 方案 A:每次转写后主动 GC
while True:
segments, _ = model.transcribe(audio="audio.mp3", language="en", initial_prompt="...", no_speech_threshold=0.2)
transcript_text = ''.join([segment.text for segment in segments])
gc.collect() # 强制回收
# 方案 B:预先解码
audio_data = faster_whisper.decode_audio("audio.mp3")
for _ in range(n):
segments, _ = model.transcribe(audio=audio_data, language="en")
transcript_text = ''.join([segment.text for segment in segments])
验证方法
运行循环转写脚本,同时通过 psutil 或系统监控工具(如 htop、SageMaker/CloudWatch 内存指标)观察进程 RSS 内存。如果内存波动范围稳定(例如基线约 1.48 GB,每个循环后无明显增长),则说明问题已解决。若使用预先解码方案,内存应完全平坦。



