实际问题
在一个项目里,需要后台运行一个php文件,这个php主要功能就是在一个永远为真的循环里,分别从Redis以及Memcache中拉取数据,然后在php中正则匹配后,把数据推回Redis。
在开发环境是没有问题的,但是上线后却发现运行了几分钟后,进程就没有异常报错的退出了,没有触发任何错误日志,让我一脸懵逼(黑人问号脸)
问题分析
确定问题
- 首先在每次循环里加入计数器,并且使用
memory_get_usage()
对每次循环的内存量进行记录。 - 发现程序每次循环次数到24500+就自动退出了,同时内存量也是一路高歌最后涨到127.3M左右就停了。
- 去到
php.ini
查找max_memory_limit
发现正好是128M。
由此确认,这个文件的异常退出就是由于运行时内存泄漏导致内存消耗量超过php配置文件上限被退出了。
定位问题
通过memory_get_usage()
以及用continue;
截断代码来不断缩减范围,配合使用来定位内存泄漏具体代码。
1 | function print_max_memory(){ |
问题总结
AnalyzeProcess.php在进程运行时,每一次while循环都发生了内存泄漏,泄漏量在7~8Kb,最后循环次数到达24500+时,达到php配置文件的内存上限128m,被强制退出。
解决问题
- 问题1
起因
使用list函数时,多定义了一个NULL的下标。
list($game, $server, $username, $role, $ip, $content,$tid) = $data;
实际上$data只有[0]-[5]一共6个下标,$tid为第7个NULL的下标,循环运行时出现内存泄漏。
解决方案
去掉这个多余的下标。
- 问题2
起因
foreach时调用了一个空的数组去做preg_match
解决方案
在preg_match匹配前做一个if判断,若为空则跳过该次循环
- 问题3
起因
用if判断了一个数组不存在的下标
解决方案
把该判断放回到正确的循环语句中
问题总结
解决这个问题后,回望代码,其实出现的问题都是因为代码不够健壮,run一次可能问题不大,但是一直while的run就发生内存泄漏问题了。故需要在码代码的时候注意一些细节的位置,让程序能够平稳运行。