PHP进程报内存耗尽,多数时候原因不是memory_limit设小了

来源:互联网 时间:2026-10-28

PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)。134217728除以两次1024,正好128M。真正该看的是最后那个20480,它说的是这一次想申请多少。报错前面通常还有一行,写着是哪个文件第几行触发的,那一行多半就在循环里。

memory_limit管的是单个请求的峰值,不是整个进程。128M的意思是这一个请求最多吃到128M,吃到就停,报错,然后php-fpm把进程回收掉。你要是看到这条报错就一路加内存,256M、512M,报错确实能安静几天。可峰值是被数据量顶上去的,数据还会继续长。tried to allocate后面那个数值得看一眼:只有几KB,说明这是最后一根稻草,前面早就吃满了;几十MB,说明就是这一次申请太大,比如一次读进整张表,或者一次解码一张大图。阈值和峰值不是一回事,把数字往上顶只是让爆的时间晚一点。

用GD处理图片最容易撞上。一张4000乘3000的JPEG,解码后在内存里按每像素4字节算,四千乘三千乘四,四十八兆左右。转成PNG再留一份副本,两个四十八兆就出去了。上传限制只卡文件体积,两兆的图解码之后要占多少,它管不着。生成缩略图也一样,画布先按原图尺寸开。

导出Excel同理。PhpSpreadsheet这类库把整张表读成内存对象,再拼XML写到输出,一万行二十列就能吃掉一个G。表现是先卡十几秒,然后这条fatal,进程被回收,浏览器拿到502。改成边查边写、一千行刷一次缓冲,峰值就压到一个批次的大小。这种改法不用动memory_limit,改完顺手把之前加过的内存降回去。任务跑在队列里的话,还得留意worker是不是也被一起撑死了。

还有一个坑是改了php.ini不生效。php-fpm的pool配置里如果写了php_admin_value[memory_limit],它的优先级高于ini_set,也高于php.ini。ini_set执行了不报错,值也没变,再查memory_get_usage还是老数。看phpinfo里的Local Value和Master Value,两个不一样就说明有东西压在上面,改php.ini没用,要去动pool的配置。

反过来,这个值也不能随便加。真正吃内存的是进程数乘单进程占用。pool里pm.max_children设成50,每个按128M算,理论上限6.4G。实际RSS通常比memory_limit还大,opcache、扩展、glibc的内存池都要算进去。一台8G的机器,MySQL先占2G,50个进程一起起来,OOM killer挑占用最大的那个杀,一般就是php-fpm。故障表现从页面报错变成整站502,查起来更费劲。加之前先把这笔账算一遍,顺便看一眼swap用了多少,那个数涨起来说明已经在拆东墙补西墙。

把峰值记下来比调参有用。脚本结束前打一行memory_get_peak_usage(true),带上当前URL,按天轮转。哪个接口的峰值高,几天就能看出来。数字在手,是改代码还是加内存,不用猜。挑三个访问量最大的页面各跑一天,比较起来就很直观。

相关文章

标签:

A5创业网 版权所有