找到分配点
内存耗尽错误会给出脚本和行号,但分配往往发生得更早。在可疑的导入、查询或响应构造前后测量峰值使用量。从几 MB 跳到几百 MB,通常说明一次性加载了整个集合。
$before = memory_get_peak_usage(true);
$rows = $pdo->query('SELECT * FROM events')->fetchAll();
$after = memory_get_peak_usage(true);
error_log("peak grew by " . ($after - $before));
流式与分块
用无缓冲或分块迭代替代 fetchAll。上传下载要流式处理,而不是 file_get_contents。大数据转换使用生成器。大引用不再需要时及时释放。没有大小限制的缓存,就是一个名字好听的泄漏。
一起规划限制
PHP 的 memory_limit 必须与容器限制兼容:容器限制应高于 PHP 限制,并为运行时和扩展留余量。容器已到上限时再提高 PHP 限制,只会改变哪一层杀死进程。
用生产规模数据验证
用有代表性的行数和文件大小运行确切失败的操作。确认峰值内存低于限制且有余量,并在并发请求下测试。只用十行夹具验证过的修复不算验证。