Debian9下Apache2与PHP7内存泄漏问题求助
遇到这种Apache+PHP内存持续飙升最后爆内存的问题,我之前在生产环境碰过好几次,咱们先一步步排查原因,再对应解决:
排查内存泄漏的根源
1. 区分是PHP脚本还是Apache本身的问题
- 先跟踪Apache子进程的内存变化:用
ps aux | grep apache2查看每个子进程的RSS(常驻内存)数值,每次运行脚本后对比同一个进程的内存变化。如果某个进程的内存只增不减,那大概率是PHP脚本/扩展的内存泄漏;如果是Apache父进程内存持续上涨,那可能是Apache模块的问题。 - 给PHP加内存监控:在脚本的关键节点(比如循环前后、大计算逻辑结束后)加入
echo memory_get_usage(true);,打印当前内存占用,定位到哪段代码导致内存飙升不释放。测试环境还可以用valgrind --leak-check=full php your_script.php直接检测PHP脚本的内存泄漏,但注意别在生产环境跑这个,会拖慢运行速度。
2. 检查Apache MPM配置(Debian默认用prefork)
- 打开
/etc/apache2/mods-available/mpm_prefork.conf,看MaxRequestPerChild值:如果是0(默认),意味着子进程会一直运行,内存泄漏会持续累积。这是很常见的坑。 - 同时检查
MaxRequestWorkers(原MaxClients)、MinSpareServers这些参数:如果设置得过大,会导致同时运行太多Apache子进程,直接吃光内存。
3. 排查PHP扩展与脚本逻辑
- 禁用非必要的PHP扩展:有些第三方扩展(比如老旧的图像处理、数据库扩展)存在内存泄漏问题。可以先在
php.ini里注释掉可疑扩展,重启Apache后测试内存是否还增长,逐个排查。 - 检查脚本中的循环引用:PHP7的垃圾回收器虽然改进了,但对象之间的循环引用(比如A对象引用B,B又引用A)可能导致内存无法自动释放。可以在循环结束后用
unset()手动销毁变量,或者调用gc_collect_cycles()强制触发垃圾回收。 - 检查资源是否未释放:比如打开大文件后没调用
fclose(),数据库结果集没手动释放,或者使用了大量临时数组却没及时清理,这些都会导致内存占用居高不下。
针对性解决办法
1. 调整Apache MPM参数缓解内存累积
- 修改
mpm_prefork.conf中的MaxRequestPerChild为500-1000(根据你的请求量调整):让每个Apache子进程处理指定数量的请求后自动重启,避免内存泄漏持续累积。 - 合理设置
MaxRequestWorkers:根据服务器总内存计算,比如每个Apache子进程大概占200MB,8GB内存的话设成30左右,避免同时运行太多进程耗尽内存。修改后记得重启Apache:systemctl restart apache2。
2. 优化PHP脚本与配置
- 开启并配置OPcache:在
php.ini中确保zend_extension=opcache.so,设置opcache.enable=1、opcache.memory_consumption=128、opcache.max_accelerated_files=10000。OPcache会缓存编译后的PHP代码,减少重复编译的内存开销,同时也能避免一些编译阶段的内存泄漏。 - 手动清理内存:在脚本的大计算、循环逻辑结束后,用
unset()释放不再需要的变量、数组或对象,必要时调用gc_collect_cycles()强制回收垃圾内存。 - 分批处理大任务:如果脚本要处理大量数据,别一次性把所有数据加载到内存,改成分批读取、分批计算,处理完一批就清理一批数据。
3. 切换到PHP-FPM(更稳定的进程管理)
如果mod_php的内存泄漏问题始终无法解决,建议切换到PHP-FPM,把PHP进程和Apache进程分开管理:
- 安装对应版本的PHP-FPM:
apt install php7.x-fpm(把7.x换成你的PHP版本,比如7.4) - 禁用mod_php:
a2dismod php7.x - 启用Apache的proxy_fcgi和setenvif模块:
a2enmod proxy_fcgi setenvif - 配置虚拟主机:在你的Apache虚拟主机配置中添加
ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:/run/php/php7.x-fpm.sock|fcgi://localhost/var/www/html/(替换/var/www/html/为你的网站根目录) - 重启服务:
systemctl restart apache2 php7.x-fpm - 然后在PHP-FPM的配置文件
/etc/php/7.x/fpm/pool.d/www.conf中设置pm.max_requests=1000,让每个FPM进程处理1000次请求后重启,从根源缓解内存泄漏。
4. 系统层面补充内存缓冲
- 检查swap空间:用
free -h查看swap使用情况,如果物理内存不足,swap可以临时缓解。如果swap不够,新增swap文件:
然后把fallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile/swapfile none swap sw 0 0添加到/etc/fstab中,让swap永久生效。
内容的提问来源于stack exchange,提问作者Flash Thunder
相关产品推荐
相关产品推荐

