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-07-23 14:49:40

    Windows10上使用Linux子系统(WSL)

    Linux的Windows子系统让开发人员可以直接在Windows上运行Linux环境(包括大多数命令行工具,实用程序和应用程序),而无需建立在虚拟机的开销之上,整个系统共200多M,但包含了你能用到的所有功能,并且和windows完美互操作(省去linux挂载本地windows分区或目录的操作),目前Linux的windows子系统已经相当完善,可当作完整linux系统使用

  • 2019-07-24 01:21:15

    android开发无障碍app

    最近做一些为盲人提供服务的APP,还是挺有感触的,感谢手机和互联网的普及,他们的生活比以前丰富了很多。 通过读屏软件,盲人可以操作手机,上网浏览信息。读屏软件的工作原理很简单,就是读出屏幕上按钮、文本的信息。

  • 2019-07-26 19:31:03

    Guacamole搭建

    因项目需要,经历多天查阅各种文档,几经波折终于功德圆满,写下此篇文章供大家分享。Guacamole就个人理解而言是一个可以通过web浏览器访问远程服务器终端进行操作的可视化工具。主要由web(浏览器)、Guacamole Server(核心)、Remote Desktops(远程桌面)三大模块组成。

  • 2019-07-30 22:36:10

    使用 Spring Initializr 初始化 Spring Boot 项目

    万事开头难,你需要设置一个目录结构存放各种项目内容,创建构建文件,并在其中加入各 种依赖。Spring Boot CLI消除了不少设置工作,但如果你更倾向于传统Java项目结构,那你应该 看看Spring Initializr。

  • 2019-08-06 15:30:08

    小程序展示富文本

    然而rich-text有个问题,它不能够给内联img设置宽度100%,这样图片就容易溢出屏幕。我们只能在后台返回富文本的时候对图片的img标签进行格式化。或者前端进行格式化也行,我赞成使用后端,因为很多种情况我们不一定都能想得到。

  • 2019-08-07 09:07:32

    最全的Service Worker讲解

    Service Worker 最主要的特点是:在页面中注册并安装成功后,运行于浏览器后台,不受页面刷新的影响,可以监听和截拦作用域范围内所有页面的 HTTP 请求。 基于 Service Worker API 的特性,结合 Fetch API、Cache API、Push API、postMessage API 和 Notification API,可以在基于浏览器的 web 应用中实现如离线缓存、消息推送、静默更新等 native 应用常见的功能,以给 web 应用提供更好更丰富的使用体验。