根本原因是/dev/shm默认64mb被pytorch共享内存缓存占满,解决方法包括临时扩容sudo mount -o remount,size=2g /dev/shm、永久修改/etc/fstab、改用spawn启动、降低num_workers、关闭pin_memory及定期清理残留文件。

根本不是显存或内存总量不够,而是共享内存(/dev/shm)被占满,或 Python 对象在 fork 时触发隐式内存复制。
为什么 num_workers > 0 会突然爆内存?
PyTorch 默认用 fork 启动 worker 进程,子进程会继承父进程的整个地址空间映射——哪怕没写入,Linux 的 copy-on-write(COW)机制也会为每个 worker 预留 /dev/shm 映射槽位。尤其当主进程已加载大模型、预分配 pinned memory 或有大量全局变量时,8 个 worker 可能共申请数 GB 共享内存页,远超默认 64MB 限制。
常见现象包括:
RuntimeError: DataLoader worker (pid X) is killed by signal: Bus error-
OSError: [Errno 12] Cannot allocate memory(不是 RAM 不足) - 训练结束后
ps aux | grep python仍看到残留的 worker 进程
怎么快速确认是 /dev/shm 耗尽?
别猜,直接查:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 运行
df -h /dev/shm:若显示64M且使用率 100%,基本锁定 - 检查 Docker 环境:默认只挂载 64MB,
docker run --shm-size=2g才够用 - 临时扩容(重启前有效):
sudo mount -o remount,size=2G /dev/shm - 永久生效需改
/etc/fstab,加一行:shm /dev/shm tmpfs defaults,size=2G 0 0,再执行sudo mount -a
ulimit -l 对此无效——它管的是 mlock() 锁定物理内存,而 PyTorch 共享内存走的是 tmpfs 路径。
pin_memory=True 和 prefetch_factor 怎么一起放大内存压力?
开启 pin_memory=True 后,每个 worker 会独立分配锁页内存池;默认 prefetch_factor=2 意味着每个 worker 预取 2 个 batch,相当于内存峰值翻倍。
- 实测:在 RTX 3060 上,
num_workers=4比=2内存峰值高 1.8GB,但吞吐仅提升 7% - 安全做法:
prefetch_factor=1(最低值),关闭冗余预取 - Windows 下更危险:锁页内存分配失败不 fallback,直接卡死或 OOM
- 若必须高并发,Linux 可改共享策略:
torch.multiprocessing.set_sharing_strategy('file_system'),避免 fork 复制 pinned buffer
哪些代码习惯会让 worker 内存持续上涨?
真正难排查的是“缓慢泄漏”,不是一次性爆掉:
- 自定义
Dataset中用list存路径/标签:Python list 是动态扩容对象,fork 时 COW 映射范围比np.array大得多;应全部转为np.array或tuple - 用了
iterable-style Dataset却配num_workers > 0:每个 worker 会完整拷贝一份 dataset 实例,数据重复加载 - 忘记设
persistent_workers=True:每 epoch 重建 worker,旧进程残留 + 新进程启动开销,内存阶梯式上升 - worker 内部加载了不可序列化的对象(如文件句柄、lambda、数据库连接),导致 fork 后状态混乱,子进程静默退出
最易被忽略的一点:即使你调小了 num_workers,只要没清理 /dev/shm 里残留的 torch_* 文件,下次启动仍可能复用旧共享内存段,直接触发冲突。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










