批量生成缩略图跑 5000 张,进程 RSS 从 180MB 涨到 3.8GB,最后被系统杀掉。每张图只有 4MB,处理逻辑里没有全局缓存,手动调 gc.collect 也没用。日志里能对上时间点,这种反而好排。

Image.open 是惰性的,文件句柄和像素数据要 close 或 with 才释放。循环里只做了 save,引用还挂在上一轮变量上。Pillow 内部的解码缓冲要等对象析构才归还,堆碎片越积越多。这一点先确认清楚,后面就不用反复试。

from PIL import Image
for p in files:
    with Image.open(p) as im:
        im.draft("RGB", (800, 800)); im.thumbnail((400, 400))
        im.save(out(p))

这次卡住的地方就在「Pillow 内存不释放」这一环,单独把它拎出来验证,别和其他改动混在同一次发布里。线上出问题先对时间点,跟发布、备份、任务执行的时刻排一排,能省掉一半功夫。

日志级别临时调高可以,记得改回去,长期开着既占磁盘又掩盖真问题。

处理上按这个顺序:用 with Image.open 保证每轮关闭;处理完显式 del 图像对象 再进下一轮;大图先 draft 降采样 减少解码内存;按批跑 每 500 张重启一次 worker 兜底。

结果对不对很好判断,跑完 5000 张后 RSS 稳定在 400MB 上下,不再随张数增长,进程没有被 OOM 杀掉。

作者 9823189