必须≤当前shell的ulimit -s值,否则swoole启动失败报“failed to set stack size: invalid argument”;因mmap(map_stack)受ulimit -s硬限制,容器中尤其需在启动脚本首行加ulimit -s 8192。

coroutine.stack_size 配置值怎么设才不报错
直接结论:必须 ≤ 当前 shell 的 ulimit -s 值,否则 Swoole 启动失败,报错 Failed to set stack size: Invalid argument。
这不是建议,是硬性限制——Swoole 调用 mmap(MAP_STACK) 分配协程栈时,内核会校验该大小是否超出主线程栈上限(即 ulimit -s)。常见踩坑点:
- 开发机默认
ulimit -s是 8192(8MB),设stack_size = 2097152(2MB)完全合法 - 但某些 Docker 镜像 base(如 alpine)默认
ulimit -s只有 1024(1MB),此时设 2MB 就直接启动失败 - 错误日志里只显示 “coroutine create failed”,根本不会提
ulimit,排查极难
生产环境务必在启动脚本开头加:ulimit -s 8192,别依赖系统默认值。
为什么 PHP 7.2 下一个协程默认占 8KB 内存
PHP 7.2 底层为每个协程预分配 8KB 用户态栈(zend_stack),不是操作系统线程栈。这个值可被 coroutine.stack_size 覆盖,但影响的是单个协程的初始内存占用,而非运行时最大用量。
验证方式很简单:
$begin_memory = memory_get_usage();
go(function () {
co::sleep(10);
});
var_dump(memory_get_usage() - $begin_memory); // 输出约 8640 字节
注意:这个 8KB 是“初始栈”,当局部变量或调用深度增加时,Zend VM 会自动扩容;但扩容代价是内存拷贝,频繁扩容反而影响性能。所以设得略宽裕(比如 128KB)比反复扩容更稳。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
stack_size 和 max_coroutine 如何协同控制内存总量
两者共同决定协程内存上限:总栈内存 ≈ max_coroutine × stack_size。例如:
-
max_coroutine = 3000,stack_size = 131072(128KB)→ 约 393MB 栈内存 - 若再开 10 个 worker 进程,仅协程栈就吃掉近 4GB 内存
而实际业务中,绝大多数协程远用不满 128KB,但一旦某个协程触发深度递归或大数组局部变量,就可能撑爆单个栈——这时不是 OOM,而是直接 Segmentation fault。
推荐做法:
- 普通 HTTP 服务:用默认 8KB 或 16KB,靠
max_coroutine控总量(如 3000~5000) - 需深度调用或处理大结构体的场景(如 LLM 流式解析):设
stack_size = 131072,同时把max_coroutine按比例压到 1000 以内 - 永远不要设
stack_size > 1048576(1MB),超过这个值,内存碎片和 mmap 开销会陡增
容器环境里 ulimit 不生效的典型表现
Docker/K8s 默认继承宿主机 ulimit,但很多基础镜像(尤其是 slim 类)在构建时没重置,导致 ulimit -s 回退到内核最小值(如 512KB)。现象是:
- 本地跑得好好的配置,一上容器就
coroutine create failed -
docker run --ulimit stack=8192:8192也不管用?因为 Swoole 启动前没执行ulimit -s,它读的是容器初始化时的值 - K8s 中需在
securityContext显式声明:runAsUser+ulimits,且必须配合容器启动脚本里的ulimit -s
最容易被忽略的一点:Swoole 的 coroutine.stack_size 是 per-coroutine 的,而 ulimit -s 是 per-process 的。一个进程里所有协程共享这个上限——哪怕你只开了 1 个协程,它的栈也不能超 ulimit -s。










