先确认是否真内存溢出:检查错误日志是否有具体文件行号、观察脚本是否卡顿、排查xdebug或超时干扰;通过memory_get_peak_usage(true)打点分析内存增长趋势,结合var_dump等调试残留清理后复测——若峰值逼近limit且错误精准指向某行(如json_decode),才算真溢出。

直接改 memory_limit 能让报错消失,但大概率掩盖了真实泄漏——先确认是不是真溢出,再决定调不调、怎么调。
怎么确认是真内存溢出,不是误判
别一见 Fatal error: Allowed memory size of XXX bytes exhausted 就去改配置。错误日志没带具体文件和行号?脚本卡几秒才崩?那很可能是 xdebug 开着、max_execution_time 超时、或 get_included_files() 返回了上百个路径(自动加载失控)。真正该看的是内存增长趋势:
- 在数据库查询前后、大循环起始/结束、
file_get_contents()调用前插入memory_get_peak_usage(true)打点,看是否阶梯式上涨 - 峰值只比当前
memory_limit低一点点,且错误明确指向某行(比如json_decode($huge_json)),才算真溢出 - 删掉所有
var_dump()、print_r()和未清理的Log::debug($data),再跑一次——很多“溢出”就消失了
CLI 和 Web 环境下,memory_limit 怎么改才生效
改错配置文件等于白改。CLI 和 Web 加载的 php.ini 完全不同,必须先确认路径:
- CLI 下运行
php --ini,看Loaded Configuration File指向哪;Web 下输出phpinfo()查Loaded Configuration File - CLI 最可靠方式是启动时加参数:
php -d memory_limit=1G script.php,不依赖任何配置,也不需重启服务 - Web 环境优先改
php.ini,改完必须重启php-fpm或 Apache;若托管环境受限,改.user.ini(需确认user_ini.filename = ".user.ini"已启用) -
.htaccess中写php_value memory_limit 512M仅在 Apache + mod_php 下有效,Nginx + PHP-FPM 不认 -
ini_set('memory_limit', '512M')必须放在脚本最开头,且不能突破php.ini里设的硬上限(比如 ini 里是128M,ini_set设512M会静默失败)
调大只是临时手段,真正省内存的实操方式
靠调 memory_limit 撑大数据量,迟早崩。更关键的是避开一次性加载:
立即学习“PHP免费学习笔记(深入)”;
- 大文件别用
file_get_contents(),改用fopen()+fgets()流式读,或封装成生成器:yield fgets($fp) - 查数据库别用
fetchAll()全量缓存结果集,改用游标分页(WHERE id > ? LIMIT 1000)或PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => false配合fetch()迭代 - 对象有循环引用(如
$child->parent = $this)时,GC 不回收,得手动打断:$obj->parent = null - JSON 解析前先判断大小:
if (strlen($json) > 5 * 1024 * 1024) { /* 改用 json-machine 等流式解析器 */ } - ThinkPHP、Laravel 等框架 CLI 命令默认
app_debug = true,SQL 日志、模板编译缓存全开——关掉它能省下 30%+ 峰值内存
最容易被忽略的一点:CLI 脚本的 memory_limit 默认常为 -1(不限制),但这反而放大了内存泄漏风险——因为没限制,泄漏就一直累积到进程退出。所以宁可设成 512M,逼自己去查哪段代码在悄悄吃内存。



















