fixedpool适用于固定大小对象的高频分配,将连续内存切分为等长slot并用单向链表管理空闲块;ringbuffer用于流式变长数据的顺序读写,基于mmap的循环缓冲区;memoryglobal是全局共享的页式内存池,线程安全但不缩容;对象池是php层对象复用机制,与c内存池无关。

FixedPool 适合固定大小对象的高频分配
FixedPool 是 Swoole 中最典型的内存池,用于分配「大小一致」的内存块,比如 swoole_table 的行结构、协程栈帧头、连接上下文等。它把一大块连续内存切分为多个等长 slot,用单向链表管理空闲块。
常见错误现象:用 FixedPool 分配变长数据(如动态 JSON 字符串),会导致频繁 fallback 到系统 malloc,失去池化意义;或误以为它支持 realloc,实际不支持扩容。
- 每次
alloc返回的指针长度严格等于初始化时设定的size - 释放必须调用对应池的
free,不能混用free()或其他池的释放函数 - 默认不线程安全,多线程访问需自行加锁(
swLock)或改用RingBuffer
RingBuffer 用于流式、变长、顺序读写的缓冲场景
RingBuffer 不是通用内存分配器,而是为 Reactor 线程收发包设计的循环缓冲区。它按需申请内存块并链成环,每个块自带长度字段,适合 TCP 流式数据拼包/拆包。
典型误用:拿它当通用堆内存替代 malloc —— 它没有空闲块回收逻辑,写满后只能整体扩容或丢弃;也不支持随机释放某一段。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 只支持追加写入(
push)和顺序读取(pop),不支持中间插入或局部释放 - 底层用
mmap映射匿名内存,避免用户态拷贝,但会占用虚拟地址空间 - 扩容时新建更大 buffer,旧数据 memcpy 过去,原 buffer 等待 GC 或显式销毁
MemoryGlobal 是全局共享、可并发分配的“大池子”
MemoryGlobal 是 Swoole 全局内存池(SwooleG.memory_pool),面向整个进程生命周期,供框架内部模块(如日志、定时器、信号处理)分配中小块内存。它基于页(swMemoryGlobal_page)管理,每页默认 64KB,内部再切分。
容易踩的坑:在 Worker 进程里大量调用 sw_malloc(即走此池)而不控制总量,会导致该池持续增长却不缩容;且它不自动归还内存给 OS,只在进程退出时整体释放。
- 线程安全:内部带
swLock,多线程可直接使用 - 不适用于超大对象(>64KB),否则会直接 fallback 到
malloc - 无法单独清理某次分配,只能等进程结束或手动调用
swMemoryGlobal_destroy
别把对象池(ObjectPool)和内存池(MemoryPool)搞混
文档里常提的「对象池」不是内存池的子类,而是上层封装:比如 Co\Redis 实例复用、swoole_http_client 连接复用,本质是 PHP 层缓存对象引用 + 复位状态,和 FixedPool 那种 C 层内存切分无关。
混淆后果:试图用 swMemoryPool 接口去管理 PHP 对象生命周期,会绕过 PHP GC,导致对象不析构、资源不关闭(如 Redis 连接未 close)。
- PHP 对象生命周期由 Zend 引用计数 + GC 控制,和 C 内存池完全解耦
- 对象池要自己实现
reset()方法清空状态,否则复用时残留旧数据 - 协程结束时,对象若被闭包捕获或存在全局引用,不会触发析构,内存池也管不到这一层
MemoryGlobal 中分配了一块内存,又把它塞进一个长期存活的 PHP 数组里,这个数组又被某个静态变量持有 —— 此时 C 层内存没泄漏,但 PHP 变量拖着它不放,协程栈、对象、池内存三者纠缠在一起,得靠 xdebug + gc_collect_cycles() + memory_get_usage() 组合排查。










