Nginx 原始碼閱讀筆記1 記憶體池

2021-07-30 07:21:38 字數 3941 閱讀 6100

在大體看完 unp 後本來想練手寫乙個小型 http 伺服器的,但是感覺少了點什麼,所以打算先學習一下 nginx 原始碼,看看大牛們是怎麼設計的。然而突然發現自己好像不怎麼了解 nginx,所以花了乙個多星期翻完了《深入理解 nginx》感興趣的部分,加強了對 nginx 的了解。計畫是以 linux 為系統環境,看完 http 核心模組,事件模組就看 epoll 模組,然後模仿著寫乙個小的(砍掉大部分功能的) http 伺服器出來。

nginx 中的記憶體池分為大塊記憶體和小塊記憶體,分別由鍊錶連線起來,此外還可以設定銷毀記憶體池時需要執行的函式,結構如下圖所示。建立與銷毀記憶體池一般由各內建模組執行,我們在開發第三方模組時一般只需要用預先構造好的記憶體池物件分配記憶體,不用手動去釋放,這樣簡化了記憶體管理,降低了犯錯的可能性。

p->d.last = (u_char *) p + sizeof(ngx_pool_t); // 可用記憶體起始位置

p->d.end = (u_char *) p + size; // 記憶體池結束位置

p->d.next = null;

p->d.failed = 0;

size = size - sizeof(ngx_pool_t); // 計算界限

p->max = (size < ngx_max_alloc_from_pool) ? size : ngx_max_alloc_from_pool;

p->current = p;

p->chain = null;

p->large = null;

p->cleanup = null;

p->log = log;

return p;

}

void

ngx_destroy_pool(ngx_pool_t *pool)

}for (l = pool->large; l; l = l->next)

}for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) }}

void

ngx_reset_pool(ngx_pool_t *pool)

}for (p = pool; p; p = p->d.next)

pool->current = pool;

pool->chain = null;

pool->large = null; // 由於存放節點的空間都是在當前各個記憶體池中分配的,所以不用 free

}

void *

ngx_palloc(ngx_pool_t *pool, size_t size)

return ngx_palloc_large(pool, size);

}void *

ngx_pnalloc(ngx_pool_t *pool, size_t size)

return ngx_palloc_large(pool, size);

}

sizemax比較,以決定是否為大塊記憶體,ngx_palloc分配的記憶體是根據ngx_alignment對齊的,ngx_pnalloc不一定是對齊的,這兩個函式的區別是呼叫ngx_palloc_small時的第三個引數,也就是決定是否需要對齊的引數

static ngx_inline void *

ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)

if ((size_t) (p->d.end - m) >= size)

p = p->d.next; // 不夠則嘗試下乙個記憶體池

} while (p);

return ngx_palloc_block(pool, size); // 現有記憶體池的剩餘空間都不足則分配新的記憶體池

}

current開始遍歷記憶體池,若找到大小足夠的記憶體池則更新last成員,返回位址,否則呼叫ngx_palloc_block分配新的記憶體池

static

void *

ngx_palloc_block(ngx_pool_t *pool, size_t size)

new = (ngx_pool_t *) m;

new->d.end = m + psize;

new->d.next = null;

new->d.failed = 0;

m += sizeof(ngx_pool_data_t); // 計算 last

m = ngx_align_ptr(m, ngx_alignment);

new->d.last = m + size;

for (p = pool->current; p->d.next; p = p->d.next)

}p->d.next = new; // 鍊錶末尾接上新分配的記憶體池

return m;

}

static

void *

ngx_palloc_large(ngx_pool_t *pool, size_t size)

n = 0;

for (large = pool->large; large; large = large->next)

if (n++ > 3)

}large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); // 從記憶體池中分配存放節點的空間

if (large == null)

large->alloc = p;

large->next = pool->large; // 接到鍊錶頭部

pool->large = large;

return p;

}

剩餘的函式邏輯較為直觀簡單,簡單地記錄下作用

函式說明

ngx_pmemalign

分配對齊的記憶體,按指定的 alignment 引數對齊,分配的記憶體被當作大塊記憶體掛在 large 鍊錶

ngx_pfree

釋放指定位址的大塊記憶體

ngx_pcalloc

呼叫 ngx_palloc 分配記憶體並清零

ngx_pool_cleanup_add

新增清理物件

ngx_pool_run_cleanup_file

執行 handler 為 ngx_pool_cleanup_file 的清理物件

下面的是提供的一些ngx_pool_cleanup_pt函式

函式說明

ngx_pool_cleanup_file

關閉指定的檔案描述符

ngx_pool_delete_file

刪除並關閉指定的檔案描述符

nginx原始碼閱讀

scr os unix下 ngx alloc.c 分配記憶體的封裝 ngx daemon c 建立守護程序。ngx thread cond.c 條件變數的封裝。ngx recv.c socket收的封裝 ngx send.c socket發的封裝 ngx shmem.c 共享記憶體的封裝 ngx s...

EventBus原始碼閱讀筆記(1)

本例子基於eventbus2.4.0的原始碼,全部筆記都以的方式呈現,因為在部落格上貼上 實在難看。1.閱讀原始碼時使用的例子,包名是com.subuju.eventbus 2.進入eventbus.getdefault 4.繼續看另乙個過載的構造方法 5.好了,執行到這裡,就完成了eventbus...

Nginx原始碼閱讀(模組)

每個nginx模組,都是乙個ngx module t型別的變數。根據ngx module t的type,所有nginx模組可以分為5種型別 type ctx指向的資料結構 commands指向的資料結構 具體模組 ngx event core module等 ngx http core module...