本文分享自天翼雲開發者社區《nginx解決進程內存佔用翻倍》.作者:z****n
1.問題
某天,線上生成環境發現一個問題:
某一台機器線上的nginx進程佔用的內存是其他機器的2倍 ,嘗試對nginx進行reload後,並沒有恢復
內存佔用翻倍機器:
正常機器:
2.分析
1.每次reload或者啓動時worker進程從master進程fork出來,所以reload後worker進程的內存和master進程內存大小應該保持一致。
2.由於master進程reload時,是先用一個全新的結構體解析配置後,再free釋放到原有配置的結構體。所以master進程再reload過程,會短暫的保持2個結構體(內存2倍),再變為1個全新配置結構體(內存正常)。所以猜測2倍的原因和這個原理有關,很可能是內存泄漏,沒有釋放原有結構體。
3.內存佔用2倍的機器上對nginx進行不斷的reload,發現內存保持不變,依然保持2倍。所以推翻第2步的猜測,若是nginx內存泄漏,那每次reload都會造成內存不斷增長,而不是一直保持2倍狀態
4.由於nginx中使用的是glibc的malloc/free, 即在程序中調用malloc 函數開闢一段空間後,再次調用free函數,程序會把開啓的空間還給glibc,但是glibc不一定會把內存還給操作系統。除非調用malloc_trim(0)。所以懷疑大概率要加上一個malloc_trim(0)
3.復現
1.準備
在本地機器上準備一個簡單的nginx,nginx中包含眾多的server{} 配置(server數量多時候比較好復現)
nginx.conf 配置如下
worker_processes 1;
error_log logs/error.log debug;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
server_names_hash_max_size 8192;
server_names_hash_bucket_size 256;
server {
listen 80;
location / {
root html;
}
}
include server/*.conf;
}
server 目錄如下中是一堆server{}塊,如下
server {
listen 80;
server_name www.a.com1;
location / {
return 200 okokokokok;
}
}
server {
listen 80;
server_name www.a.com2;
location / {
return 200 okokokokok;
}
}
####大量不同server_name 的server{}
2.測試
啓動nginx,觀察當前內存
進行reload 操作,觀察當前內存,發現內存翻了一倍
4.解決
在 src/os/unix/ngx_process_cycle.c 中 解析完新配置釋放舊的配置的結構體後,增加一行 malloc_trim(0)後,重新編譯。再次啓動nginx, reload後,觀察內存不會翻倍
有的nginx中使用了jemalloc中替換了glibc也可能遇到這個問題,需要把malloc_trim函數 替換為mallctl函數,同時加上3個jemalloc的頭文件,差別如下
12,15d11
< #include <jemalloc/jemalloc.h>
< #include <jemalloc/internal/jemalloc_internal_defs.h>
< #include <jemalloc/internal/util.h>
<
235c231
< mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", NULL, NULL, NULL, 0);
---
> malloc_trim(0);