Python中fork时提示无法分配内存,但服务器内存充足
解决线程中重复fork出现Errno 12内存不足的问题
这种情况我之前排查过类似的,虽然你已经排除了僵尸进程和物理内存不足的问题,但还有几个容易被忽略的关键点可能导致这个错误,咱们一步步分析:
1. 用户进程数上限被耗尽
系统默认会给每个用户设置最大进程数限制(RLIMIT_NPROC),哪怕物理内存还有剩余,只要进程数达到上限,就会报内存不足的错误。
你可以先在服务器上执行这个命令查看当前限制:
ulimit -u
再用这个命令统计当前用户已创建的进程数:
ps -u $(whoami) | wc -l
如果已用进程数接近上限,要么联系管理员调高限制,要么在代码里用resource模块动态调整(需要对应权限):
import resource # 查看当前进程数的软/硬限制 soft_limit, hard_limit = resource.getrlimit(resource.RLIMIT_NPROC) print(f"进程数限制: 软限制{soft_limit}, 硬限制{hard_limit}") # 临时调高软限制(硬限制需要root权限才能修改) resource.setrlimit(resource.RLIMIT_NPROC, (soft_limit + 50, hard_limit))
2. 线程中fork的兼容性隐患
这是最容易踩坑的点:在多线程环境下调用fork()本身就不安全!
fork只会复制当前调用fork的线程,其他线程的状态不会被复制。如果其他线程当时持有锁(比如Python的GIL、文件锁或者自定义锁),fork后的子进程里这些锁会处于永久锁定状态,导致资源泄漏、内存无法释放,后续再fork时就会出现异常。
解决思路:
- 尽量不在线程中执行fork,把进程创建逻辑移到主线程中;
- 如果必须在线程里fork,那fork后要立即调用
exec系列函数(比如os.execvp)替换子进程的地址空间,避免继承父线程的不良状态; - 更稳妥的方式是用Python的
multiprocessing模块创建子进程,它内部已经处理了多线程下fork的安全问题,比手动调用os.fork可靠得多。
3. 虚拟内存或地址空间耗尽
64位系统虽然虚拟地址空间很大,但如果每个子进程占用大量地址空间(比如打开了很多文件、加载了大库),累积起来也可能耗尽虚拟内存。你可以用以下命令排查:
# 查看虚拟内存和swap使用情况 free -h # 查看内存状态和碎片情况 vmstat
另外要确保子进程退出时彻底释放了所有资源:关闭文件句柄、断开网络连接、清理临时数据等,这些资源残留会占用地址空间,导致后续分配失败。
4. 内存碎片问题
即使总内存充足,内存碎片过多也可能导致无法分配连续的内存块给新进程。这种情况可以尝试临时整理内存(需要root权限):
echo 1 > /proc/sys/vm/compact_memory
不过这只是临时方案,长远来看要优化子进程的内存使用,减少不必要的内存分配。
内容的提问来源于stack exchange,提问作者Rodrigo Formighieri
相关产品推荐
相关产品推荐

