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

以前遇到過一次服務器內存告警,查看後發現有個php-fpm進程佔用了2G的內存。但我明明在php.ini文件裏面,有配置 memory_limit = 256M,那爲何會有佔用2G內存的php-fpm進程呢?php

這裏先簡單說一下nginx+php-fpm模式的工做原理。
這裏寫圖片描述nginx

  1. nginx服務器fork出n個子進程(worker),php-fpm管理器fork出n個子進程。
  2. 當有用戶請求,nginx的一個worker接收請求,並將請求拋到socket中。
  3. 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進程佔用的內存愈來愈大。socket

那麼,有什麼辦法能阻止這個問題呢?方法一:寫不泄漏內存的php程序;方法二:在php-fpm配置文件中,將pm.max_requests這 個參數設置小一點。這個參數的含義是:一個php-fpm子進程最多處理pm.max_requests個用戶請求後,就會被銷燬。當一個php-fpm 進程被銷燬後,它所佔用的全部內存都會被回收。php-fpm

如下是我本身作的一次測試:測試

首先:將php-fpm.conf裏面pm.max_chindren參數設爲1。這意味着,php-fpm管理器只會fork出一個php-fpm子進程。這樣一來,用戶的每次請求,都會讓這個進程來處理。而後隨便請求我本身的網站,會看到有以下結果:
這裏寫圖片描述
能夠看到,那個php-fpm子進程佔用的內存愈來愈大。網站

而後我將php-fpm重啓一下:
這裏寫圖片描述
能夠看到php-fpm子進程佔用的內存馬上變小了。code

最後我將pm.max_requests這個參數設爲5,而後再隨便請求幾回個人網站,看一下結果:
這裏寫圖片描述
能夠看到,php-fpm子進程的進程id會自動變化。這說明,php-fpm子進程確實會自動被銷燬,而後再產生新的php-fpm子進程,並且php-fpm子進程佔用的內存也沒有愈來愈大。生命週期

相關文章
相關標籤/搜索