php8.5session垃圾回收变了_php8.5sessiongc清理机制变化

2次阅读

php 8.5 彻底移除 session.gc_probability/session.gc_divisor 的概率触发机制,gc 改为仅在 session_start() 时按需延迟执行:需同时满足存在过期文件且距上次 gc 超过 session.gc_maxlifetime。

php8.5session垃圾回收变了_php8.5sessiongc清理机制变化

PHP 8.5 的 session.gc_probabilitysession.gc_divisor 不再控制实际触发概率

PHP 8.5 彻底移除了基于概率的 session 垃圾回收(GC)触发机制。以前靠 session.gc_probability/session.gc_divisor 控制“每多少次请求执行一次 GC”,现在这个逻辑被废弃了——无论你设成 1/100 还是 0/1,都不会影响 GC 是否运行。

原因很简单:PHP 内部改用「按需延迟触发」模型,GC 只在 session_start() 时,且满足两个条件才真正执行:一是当前 session.save_path 下存在过期文件(filemtime 超过 session.gc_maxlifetime),二是上一次 GC 时间距今已超 session.gc_maxlifetime(默认 1440 秒)。

  • 旧配置仍可写,但完全被忽略;修改它们不会带来任何行为变化
  • session.gc_probability = 0 不再能“禁用 GC”——它只是个无效开关
  • 如果你依赖旧版概率触发做监控或日志埋点,这部分逻辑会失效

session.gc_maxlifetime 现在同时决定过期判断 + GC 触发间隔

在 PHP 8.5 中,session.gc_maxlifetime 的语义变重了:它既是 session 数据文件的“存活时长上限”,也是 GC 扫描周期的硬性间隔。也就是说,哪怕你每秒调用 100 次 session_start(),GC 最多每 session.gc_maxlifetime 秒执行一次,且只清理那些 filemtime 小于 time() - session.gc_maxlifetime 的文件。

  • 若你把 session.gc_maxlifetime 设为 300(5 分钟),GC 最快也得等满 5 分钟才可能再跑一次
  • 该值必须与前端 cookieMax-Age / Expires 对齐,否则会出现“用户还在线,但服务端 session 已被删”的错位
  • 使用 redismemcached 存储 session 时,此配置仅影响 PHP 自己的文件扫描逻辑,后端存储的过期由自身 TTL 控制,两者需独立协调

自定义 session handler 必须显式实现 GC 逻辑

如果你用了 SessionHandlerInterface 实现自定义 session 处理器(比如对接数据库对象存储),PHP 8.5 不再代你调用 gc() 方法——除非你在 session_start() 前手动触发,或者自己加定时任务。

立即学习PHP免费学习笔记(深入)”;

旧代码里依赖“PHP 自动调用 gc()”来清理过期记录的,现在会持续累积脏数据。

  • 检查你的 gc() 方法是否还在被调用:加日志或断点,发现没执行就是被跳过了
  • 推荐在应用启动时或低峰期主动调用一次 $handler->gc($maxlifetime)
  • 不要在 read()write() 里嵌套 GC 清理,容易引发并发写冲突或性能抖动

验证 GC 是否真的在工作:别信 phpinfo(),要看文件时间戳

phpinfo() 里显示的 session.gc_* 配置项还是老样子,但这只是残留字段,不能反映真实行为。要确认 GC 是否生效,得直接看 session.save_path 目录下的文件:

ls -lt /var/lib/php/sessions/ | head -10

观察 sess_* 文件的修改时间(mtime)。如果大量文件的 mtime 明显早于 time() - session.gc_maxlifetime 却没被删除,说明 GC 没触发或失败。

  • 常见干扰项:目录权限不对(PHP 进程无法 unlink)、NFS 挂载导致 filemtime() 不准、SELinux 限制
  • 错误信息如 Warning: Unknown: Failed to write session data (files) 可能掩盖 GC 失败,需查 error_log
  • strace -e trace=unlink,stat64 -p $(pgrep php-fpm) 可抓到实际的清理系统调用

GC 的边界其实很窄:它只管“删过期文件”,不负责锁清理、内存释放或外部存储同步。这些都得你自己兜底。

text=ZqhQzanResources