nginx+php-fpm模式php内存泄漏探究

2018-12-26 16:12:56

之前遇到过一次服务器内存告警,查看后发现有个php-fpm进程占用了2G的内存。但我明明在php.ini文件里面,有配置 memory_limit = 256M,那为什么会有占用2G内存的php-fpm进程呢?


这里先简单说一下nginx+php-fpm模式的工作原理。 



nginx服务器fork出n个子进程(worker),php-fpm管理器fork出n个子进程。

当有用户请求,nginx的一个worker接收请求,并将请求抛到socket中。

php-fpm空闲的子进程监听到socket中有请求,接收并处理请求。

这里要重点说一下第三步骤。第三步涉及到php-fpm进程生命周期的东西。一个php-fpm的生命周期大致是这样的:模块初始化(MINIT)-> 模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN) -> 模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN)……. 模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN)-> 模块关闭(MSHUTDOWN)。在一个php-fpm进程的生命周期里,会有多次的模块激活(RINIT)-> 请求处理 -> 模块停用(RSHUTDOWN)的过程。这个“请求处理”的大致过程是这样的:php读取相应的php文件,对其进行词法分析,生成opcode,zend虚拟机执行opcode。


回到一开始说的PHP配置文件里面的memory_limit 这个东西,其实,它限制的只是这个“请求处理”的内存。所以,这个参数跟php-fpm进程占用的内存并没有什么关系。那为什么会有占用2G大小的php-fpm进程呢?原因是这样的:php是用c写的,所以,难免又会一些内存泄露。也就是说,在“请求处理”这个过程结束后,有些变量没有被销毁,然后就导致一个php-fpm进程占用的内存越来越大。


那么,有什么办法能阻止这个问题呢?方法一:写不泄漏内存的php程序;方法二:在php-fpm配置文件中,将pm.max_requests这个参数设置小一点。这个参数的含义是:一个php-fpm子进程最多处理pm.max_requests个用户请求后,就会被销毁。当一个php-fpm进程被销毁后,它所占用的所有内存都会被回收。


以下是我自己做的一次测试:


首先:将php-fpm.conf里面pm.max_chindren参数设为1。这意味着,php-fpm管理器只会fork出一个php-fpm子进程。这样一来,用户的每次请求,都会让这个进程来处理。然后随便请求我自己的网站,会看到有如下结果: 

 

可以看到,那个php-fpm子进程占用的内存越来越大。


然后我将php-fpm重启一下: 

 

可以看到php-fpm子进程占用的内存立刻变小了。


最后我将pm.max_requests这个参数设为5,然后再随便请求几次我的网站,看一下结果: 

 

可以看到,php-fpm子进程的进程id会自动变化。这说明,php-fpm子进程确实会自动被销毁,然后再产生新的php-fpm子进程,而且php-fpm子进程占用的内存也没有越来越大。


  • 2019-03-13 09:38:11

    写入MySQL报错超出 max_allowed_packet 的问题

    MySQL会根据配置文件会限制server接受的数据包的大小。如果写入大数据时,因为默认的配置太小,插入和更新操作会因为 max_allowed_packet 参数限制,而导致失败。

  • 2019-03-15 15:28:33

    10分钟教你搭建自己的ngrok服务器

    内网穿透想必开发过微信的同志都很了解,大部分人选择网上寻找各种现成的,比如ngrok官网、ittun-ngrok、sunny-ngrok或者花生壳之类的。但是世界上没有免费的午餐,要不就是收费,要不就是免费但是偶尔会出现连接失败的问题(当然大多数时间是没有问题的)。

  • 2019-03-15 15:29:53

    丢弃花生壳,搭建自己的ngrok作为内网穿透服务器

    公司没有公网,公司在二级路由下面(就是服务商没有给独立IP,也无法动态获取公网IP),然而公司在开发程序的时候,如对接微信等需要返回数据,或者需要别人能访问我们网址,一般我们就只能购买花生壳内网穿透,但是在使用中发现速度慢,经常掉。所以搭建自己的ngrok服务器来保证内网穿透。

  • 2019-03-15 15:31:21

    内网穿透 ngrok 服务器和客户端配置

    ngrok 简介及作用 ngrok 是一款用 go 语言开发的开源软件,它是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。下图简述了 ngrok 的原理。

  • 2019-03-15 15:32:09

    内网打洞以及代码实现

    假设内网的多个ip或者同一ip的不同port,都要访问同一个(外网ip:port)。对NAT来说,从外网接收的包它的(srcIp:srcPort)==(serverIp,serverPort),它的dstIp==natIp,所以NAT只能用dstPort来决定把这个包转发给哪一个(内网Ip:port)

  • 2019-03-15 15:33:08

    Xshell不能按退格、删除键的解决方案

    在使用xshell时,由于每个服务器不同,一些无法使用Backspace键向后删除字符。针对这个问题,本文为大家解答下退格键无法识别如何设置?

  • 2019-03-15 15:49:28

    win10远程桌面连接不上解决方法

    有朋友就感叹电脑的世界真的是很神奇,可以将整个世界连接在一起。如果别人想要摆弄你的电脑,即使不在一个地方也可以利用远程桌面来控制。而这就是所谓的远程控制操作了,大部分人都知道它的作用,不过这也不排除会遇到一些突发情况的时候,例如win10远程桌面连接不上,这该怎么去解决呢?为此,小编给大家带来了解决的图文操作。

  • 2019-03-15 16:49:18

    Win7无法进入家庭组提示“您的系统管理员不允许访问家庭组”怎么办

     家庭组是家庭网络上可以共享文件和打印机的一组计算机,可以方便用户们共享文件或者视频等,可是最近有win7纯净版系统用户却发现无法进入家庭组,提示“您的系统管理员不允许访问家庭组”,该怎么办呢?现在给大家分享一下Win7无法进入家庭组提示“您的系统管理员不允许访问家庭组”的解决方法。