webman 中禁用 static 数组作内存表,因其常驻进程不释放易致 oom;应改用带 ttl 的 apcu 缓存、redis hash(支持过期/原子操作/跨 worker 共享)或请求级临时数组。

Webman 里用 static 数组当“内存表”极易泄漏
别把 static $data = [] 当成轻量级内存表来用——它在 Webman 常驻进程中永不释放,只要业务逻辑往里无节制 push,内存就一路涨到 OOM。压测时 100 并发跑 30 秒,64MB → 383MB 不是异常,是必然结果。
- 真正需要的是有生命周期控制的数据结构,比如按请求 scope 创建的临时数组,或带 TTL 的缓存对象
- 若真要模拟表格行为,优先用
apcu_store()+apcu_fetch(),配合键名约定(如"user_table_{$uid}")实现逻辑分表 - 绝对避免在全局作用域、中间件、事件监听器里长期持有大数组引用,尤其不能在协程外反复 append
用 Redis Hash 模拟内存表更安全可靠
Webman 本身不提供“内存表”原生组件,但 Redis 的 HSET/HGETALL 天然适合做结构化内存表,且自带过期、原子操作和跨 worker 共享能力。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 写入:用
$redis->hSet('log_table_202606', $id, json_encode($row))替代array_push($table, $row) - 查询:用
$redis->hGetAll('log_table_202606')获取全量,或$redis->hMGet('log_table_202606', ['1001','1002'])精确捞行 - 注意设置
EXPIRE,例如$redis->expire('log_table_202606', 3600),防止冷数据堆积 - 不要用
KEYS log_table_*扫描,改用SCAN避免阻塞
高频读写场景下,慎用 PHP 数组模拟二维表
哪怕你控制了 size,PHP 数组在 Webman 中仍会随 worker 生命周期持续驻留。10 万行 × 20 字段的二维数组,内存占用轻松破 150MB,且 GC 无法及时回收。
- 单次请求内需要临时查表?用
array_column($rows, 'value', 'id')构建哈希映射,用完即弃 - 需跨请求共享小规模配置表(如状态码映射)?走
config/目录下的 PHP 文件,靠 opcode 缓存加载,不占堆内存 - 真要加载百万行做关联?放弃内存表思路,直接 SQL JOIN 或用 MySQL 临时表 +
CREATE TEMPORARY TABLE
协程环境下,别忽略连接池对“内存表”语义的干扰
Webman 使用 Swoole 协程 MySQL 连接池时,DB::table('xxx')->get() 返回的结果集本质仍是 PHP 数组——但它背后绑定的是复用的 PDO 实例,若你在循环中不断 array_merge 多次查询结果,等于在协程栈上累积副本。
- 分页查,别
offset/limit后全取再合并;用游标(如WHERE id > ? ORDER BY id LIMIT 1000)边读边处理 - 批量插入前调用
gc_collect_cycles(),尤其在长循环末尾,能缓解内存抖动 - 日志类“内存表”写入,务必用
go(function () { Log::write(...); })脱离主协程上下文,防阻塞










