ngx_shmem的使用
ngx_shmem.c/h檔案只是對mmap()/munmap()系統呼叫或shmget()/shmdt()的一個很簡單的封裝。實現了ngx風格的基礎庫,可以申請並釋放一段連續的共享記憶體空間。一般用於固定長度的共享資料使用,使用過程中資料長度固定不會伸縮。
typedef struct { u_char *addr; size_t size; ... } ngx_shm_t; ngx_int_t ngx_shm_alloc(ngx_shm_t *shm); void ngx_shm_free(ngx_shm_t *shm);
在ngxin中共享記憶體的使用流程,一般是由master進程創建,worker進程透過繼承的方式獲得記憶體指標。
關於ngx_shmem的使用,可以參考ngx_event_module_init()中部分片段,這部分程式碼在共享記憶體中創建了若干個變量,用於記錄各個狀態(accepted/reading/writing...)的請求數量,並在ngx_event_module中的幾個關鍵事件入口對這幾個變數進行加減統計操作。實作統計所有worker進程目前的請求狀態。
shm.size = size; ngx_str_set(&shm.name, "nginx_shared_zone"); shm.log = cycle->log; if (ngx_shm_alloc(&shm) != ngx_ok) { return ngx_error; } shared = shm.addr; ... ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); ngx_stat_waiting = (ngx_atomic_t *) (shared + 9 * cl);
關於這個功能的更多細節,可以查看程式碼中的ngx_stat_stub巨集定義相關程式碼與ngx_http_stub_status_module。
ngx_slab的使用
ngx_shmem是一層極簡的封裝,實作了共享記憶體的基本功能。但我們程式中大部分的場景共享資料並不會一個固定大小的結構,而更多是像ngx_array、ngx_list、ngx_queue、ngx_rbtree這類大小可以變化的資料結構。
我們預期能有像ngx_pool_t一樣可以動態申請釋放空間一個記憶體池。 ngx_slab正是一個這樣的結構體,原理上與系統的malloc()有相識之處都是透過一系列演算法實現對一段段記憶體片段的申請與釋放。只不過ngx_slab操作的物件是基於ngx_shmem的共享記憶體。
先看一下ngx_slab的介面
typedef struct { ngx_shmtx_t mutex; ... void *data; /* 一般存放从pool中申请获得的根数据地址(pool中第一个申请的数据接口) */ void *addr; /* 使用ngx_shmem申请获得的共享内存基地址 */ } ngx_slab_pool_t; void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size); void ngx_slab_free(ngx_slab_pool_t *pool, void *p); void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
可以看到介面並不復雜,alloc與calloc的區別在於是否對申請獲得的記憶體段清零,_locked結尾的介面表示操作的pool已經是取得到鎖定的。在ngx_slab_pool_t的結構體有一個ngx_shmtx_t的互斥鎖用於同步多進程同時存取pool的並發場景。注意ngx_slab_alloc()會先取得鎖定、然後申請空間、最後釋放鎖定。而ngx_slab_alloc_locked()則直接申請空間,認為程式已經在其他邏輯中獲得鎖定了。
在nginx的開發中使用ngx_shmem一般需要遵循以下初始化流程:
模組在配置解析過程中調用ngx_shared_memory_add()接口,註冊一段共享記憶體。提供共享記憶體大小與記憶體初始化的回呼函數。
框架在ngx_init_cycle()中使用ngx_shmem申請內存,並初始化ngx_slab,然後回調模組註冊的初始化函數
#模組使用ngx_slab的申請/是否介面
在這個流程中,涉及ngx_shared_memory_add()介面與對應的ngx_shm_zone_t結構體。
struct ngx_shm_zone_s { void *data; ngx_shm_t shm; ngx_shm_zone_init_pt init; void *tag; void *sync; ngx_uint_t noreuse; /* unsigned noreuse:1; */ }; ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag);
其中值得一提的是noreuse屬性,這個屬性控制了在nginx的reload過程中是否會重新申請共享記憶體。
由於關於ngx_init_cycle()函數較長,這個流程可以透過尋找/* create shared memory */這個註解或cycle->shared_memory這個物件查看相關程式碼。
以上是nginx中的共享記憶體如何使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!