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

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

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

  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進程佔用的內存越來越大。

那麼,有什麼辦法能阻止這個問題呢?方法一:寫不泄漏內存的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子進程佔用的內存也沒有越來越大。

發佈了33 篇原創文章 · 獲贊 3 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章