很长一段时间以来,我注意到工作在FastCGI模式下的PHP会占用越来越多的内存,而且似乎从不释放。起初我以为这是内存泄漏的问题,但是各个PHP社区的人好像并没有把这个当作问题。我搜索了一下,发现还有不少人面临同样的问题。来自PHP官方的一个比较正式的解释是:php-cgi进程并没有内存泄漏,php-cgi会在每个请求结束的时候回收脚本使用的全部内存,但是并不会释放给操作系统,而是继续持有以应对下一次PHP请求。这样做大概是为了减少内存碎片化或者解决从系统申请内存之后又释放回操作系统所需要的时间不可控问题。可是如果偶然一次PHP请求使用了诸如ftp或者zlib这样的大内存操作,那么将导致一大块系统内存被php-cgi持续占有,不能被利用。
解决这个问题的办法是在web服务器配置中降低PHP_FCGI_MAX_REQUESTS的值。这个参数决定了一个php-cgi进程被创建出来之后,最多接受的PHP请求数,在lighttpd中默认配置是10000。也就是说这个php-cgi进程每接受10000次PHP请求后会终止,释放所有内存,并重新被管理进程启动。如果把它降低,比如改成100,那么php-cgi重启的周期会大大缩短,偶然的高内存操作造成的问题影响时间也会缩短。
另一个办法则是写一个crontab脚本,定时发现高内存占用的php-cgi进程并向它传送kill指令。