先用memory_get_usage(true)和memory_get_peak_usage(true)在关键位置打点确认是否真溢出,再排查var_dump调试、xdebug启用、超时误判等假性问题;CLI用php -d参数,Web按php.ini→.user.ini→ini_set()优先级调整,数据库查百万行改fetch迭代,大文件用fopen()+fgets()流式读取,JSON解析加参数或换流式parser,循环引用需手动打断。

memory_limit 能临时绕过“Allowed memory size of XXX bytes exhausted”错误,但**不能解决内存持续增长的根本问题**。真正在吃内存的,往往是未释放的资源、全量加载的数据或循环引用——先确认是不是真溢出,再决定要不要调。
怎么确认是真内存溢出,不是误判?
别一见报错就改配置。先用 memory_get_usage(true) 和 memory_get_peak_usage(true) 在关键位置打点,比如数据库查询后、大文件读取前、循环开始/结束处,看内存是否阶梯式上涨。如果峰值只比 memory_limit 低一点,且错误日志明确指向某行(如 file_get_contents() 或 json_decode()),那才是真溢出。
常见假性溢出:
- 调试时用了
var_dump($huge_array),删掉就恢复 - 脚本卡住几秒后报错,其实是
max_execution_time超时被误读为 OOM - 启用了
xdebug.mode=debug,单步调试本身吃内存;关掉再试:php -d zend_extension= -f script.php -
get_included_files()返回上百个路径,说明重复require或自动加载失控
CLI 和 Web 环境下,memory_limit 怎么改才生效?
不同运行模式加载的配置文件可能完全不同,改错地方等于白改。
CLI 模式最可靠方式是启动时加参数:php -d memory_limit=1G script.php。它不依赖任何配置文件,也不需要重启服务。
立即学习“PHP免费学习笔记(深入)”;
Web 环境优先级顺序是:php.ini → .user.ini(需启用 user_ini.filename)→ .htaccess(仅 Apache mod_php 有效)→ ini_set()(仅对后续分配生效)。
注意:
-
ini_set('memory_limit', '512M')必须写在脚本最开头,且不能高于php.ini中的硬上限(除非设为-1) -
.htaccess中写法必须是php_value memory_limit 384M,单位必须大写,不能有空格 -
php-fpm下.htaccess完全无效,.user.ini是更通用的替代方案 - 改完
php.ini后,必须重启php-fpm或 Apache,reload不够
哪些操作真正吃内存?对应怎么优化?
调高限制只是兜底,以下操作才是内存大户,改代码比改配置更治本:
- 数据库查百万行:禁用
PDO::FETCH_ASSOC全缓存,改用$stmt->fetch()迭代,或设置PDO::MYSQL_ATTR_USE_BUFFERED_QUERY = false关闭缓冲 - 读 GB 级文件:扔掉
file_get_contents(),改用fopen()+fgets()流式读取,或封装成生成器:yield fgets($fp) - 解析超长 JSON:避免
json_decode($json)整树加载,加参数JSON_BIGINT_AS_STRING防止数字转 float,或换用流式 parser 类库 - 对象循环引用:PDO 对象持有 statement,statement 又反向引用连接;处理完记得
$stmt->closeCursor()和$pdo = null - 大数组分片处理:用
array_chunk($data, 1000)切块,每轮处理完立刻unset($chunk)
为什么 unset() 了变量,内存还是没下来?
PHP 的垃圾回收对循环引用无效。一个对象即使被 unset(),只要还有其他变量强引用它(比如 $obj->parent 指向父对象,父对象又存着 $obj),就不会释放。
真正要做的,是在确定不再需要时主动打断引用链:
$obj->parent = null;$obj->children = [];- 文件句柄必须
fclose($fp),否则底层缓冲区和文件描述符一直占着 - GD 图像资源用完后调
imagedestroy($img)
最易忽略的是 PDOStatement 内部结果集——它不调 closeCursor(),哪怕连接已关闭,内存也不会还。



















