Linux环境下PHP服务内存占用过高问题及优化咨询
解决Docker部署的PHP服务内存占用过高且无法释放的问题
嘿,我来帮你搞定这个Docker里PHP服务内存飙到4GB还不自动释放的麻烦!先梳理下你的场景:你跑了个死循环的PHP脚本,每隔15秒执行一次数据处理、DB查询、API调用和日志写入,同时用Docker里的Supervisor管理cron服务。问题的核心在于这个长期常驻的PHP进程,加上脚本内可能存在未及时释放的资源,导致内存持续累积。下面给你按优先级排序的优化方案:
1. 优先重构:把常驻进程改成定时任务(最稳妥)
PHP的CLI模式天生适合一次性执行的脚本,进程结束后会自动释放所有内存,从根源上避免内存泄漏。你完全不需要让脚本一直跑,改成定时触发就行:
- 先把脚本改成单次执行版本(去掉外层的
while(1){ sleep(15); ... },只保留单次处理逻辑) - 用cron实现15秒间隔的触发:如果系统支持精细定时,或者写个小bash脚本配合cron:
然后在cron里设置每分钟执行这个bash脚本:# 比如创建run_every_15s.sh #!/bin/bash for i in {1..4}; do php /path/to/your/script.php sleep 15 done* * * * * /path/to/run_every_15s.sh,这样就能实现每15秒执行一次PHP脚本,每次执行完进程就退出,内存全释放。
2. 修复脚本内的内存泄漏(如果非要保留常驻进程)
如果业务场景必须让脚本常驻运行,那就要手动管理内存和资源:
- 每次循环结束后,主动释放变量并触发垃圾回收:
unset($data, $d); // 释放循环内的变量 gc_collect_cycles(); // 强制触发PHP垃圾回收 - 数据库操作:确保每次查询后关闭连接,比如用PDO的话,用完后设置
$pdo = null;,不要用持久化连接(PDO::ATTR_PERSISTENT => false) - API调用:如果用curl,每次调用后必须关闭句柄:
curl_close($ch);,避免句柄和内存泄漏 - 日志写入:如果是手动打开文件句柄,写完后一定要
fclose($fp);,不要长期保持文件打开状态
3. 给Docker设置内存限制(兜底方案)
不管怎么优化,都可以给Docker容器设置内存上限,防止它占用过多主机资源:
- 在
docker run命令里添加参数:--memory=1g --memory-swap=1g(限制容器最多用1GB内存,超过会触发OOM kill) - 如果用docker-compose,在服务配置里加:
配合Supervisor的自动重启配置,就算进程被OOM杀死,也能自动恢复。services: your-service: # ...其他配置 deploy: resources: limits: memory: 1g
4. 调整Supervisor配置(适配你的服务)
你的当前Supervisor配置是管理cron,但如果是直接运行常驻PHP脚本,应该把Supervisor指向PHP脚本本身:
[program:php-data-service] command=php /path/to/your/script.php autostart=true autorestart=true startretries=3 stdout_logfile=/var/log/php-service.log stderr_logfile=/var/log/php-service.err.log user=www-data stopasgroup=true ; 确保停止进程时连带子进程一起关闭
这样Supervisor能直接监控PHP进程的状态,异常退出时自动重启。
内容的提问来源于stack exchange,提问作者Tuz
相关产品推荐
相关产品推荐

