根本原因是/dev/shm默认64MB被PyTorch共享内存缓存占满,ulimit -l无效因其控制mlock而非tmpfs;应通过df -h /dev/shm确认占用,再用sudo mount -o remount,size=2G /dev/shm临时扩容或修改/etc/fstab永久生效。

根本原因不是内存或显存不够,而是 /dev/shm 默认大小(64MB)被 PyTorch 的共享内存缓存快速占满,尤其在 num_workers > 0 且 pin_memory=True 时。
为什么 ulimit -l unlimited 完全无效
ulimit -l 控制的是 mlock() 锁定物理内存的上限,而 PyTorch 的共享内存走的是 shm_open() + mmap() 路径,依赖 /dev/shm 这个 tmpfs 文件系统。两者完全不相关。
- 运行
ulimit -l查看当前值(单位 KB),通常为 64,但它不影响/dev/shm容量 - 设成
unlimited不仅没用,还可能干扰 RDMA 或其他依赖mlock的组件 - 真正要调的是
/dev/shm本身大小,不是这个 limit
如何快速确认是 /dev/shm 溢出
训练卡住或 worker 随机退出时,别急着改代码,先验证是否真卡在这里:
- 在宿主机或容器内运行
df -h /dev/shm:若显示64M且Use%接近 100%,基本就是它 - 查残留文件:
ls -la /dev/shm/ | grep torch,常能看到大量torch_*前缀的未清理共享对象 - Docker 环境下额外检查:
docker inspect <container_id> | grep ShmSize</container_id>,默认往往就是64M
临时 vs 永久扩容 /dev/shm 的实操要点
扩容不是越大越好,Linux 内核对 tmpfs 有硬限制,盲目设到 8G+ 反而容易触发 OOM killer。
立即学习“Python免费学习笔记(深入)”;
- 临时生效(重启前有效):
sudo mount -o remount,size=2G /dev/shm - 永久生效:编辑
/etc/fstab,加一行shm /dev/shm tmpfs defaults,size=2G 0 0,再执行sudo mount -a - Docker 启动时直接指定:
docker run --shm-size=2g ...,比进容器里 remount 更可靠 - PyTorch 1.12+ 改用
spawn启动方式能缓解但不能绕过——它减少 fork 复制的地址空间映射槽位,但仍需按需创建共享内存对象
更轻量的规避方案:降低共享内存压力
如果无法改系统配置(比如在受限生产环境),优先从 PyTorch 使用侧入手:
- 把
pin_memory=True改成False:这是最猛的减压手段,尤其对小 batch 或非高分辨率数据效果明显 - 逐步调低
num_workers:从 8 → 4 → 2 测试,找到性能与稳定性平衡点 - 避免在
Dataset.__getitem__中返回未处理的大张量(如原始图像 ndarray),先转成 PIL 或做简单裁剪再转 tensor - 训练结束后手动清理:
import torch.multiprocessing as mp; mp.set_sharing_strategy('file_system')(部分版本可用,但不如调/dev/shm稳定)
真正麻烦的不是调大小,而是问题表现隐蔽——崩溃常发生在第 37 个 epoch、第 124 个 batch,且日志里只报 worker exit code 1。所以一旦怀疑,立刻 df -h /dev/shm,比翻代码快十倍。


















