在src/core/ngx_palloc.h中定義了記憶體池相關的結構體
**記憶體相關的
//記憶體池**結構體
struct ngx_pool_cleanup_s ;
//大塊資料分配結構體
struct ngx_pool_large_s ;
//記憶體池中資料結構體
typedef struct ngx_pool_data_t;
//記憶體池管理結構體
struct ngx_pool_s ;
//其他結構體
typedef struct ngx_pool_cleanup_file_t;
乍一看這些結構體的關係有點混亂啊,別急,咱來看一段記憶體池建立的**
src/core/ngx_palloc.c檔案中
ngx_pool_t *
ngx_create_pool(size_t size, ngx_log_t *log)
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;
}
建立後結果如下圖所示:
看完了建立記憶體池的**,再來看看nginx是如何從記憶體池中分配所需要的記憶體的吧,**如下:
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
p = p->d.next;
} while (p);
/*如果所有的pool都沒有可供分配的size大小空間,則新建立乙個pool,並將該pool中分配空間的首位址返回。
*/ return ngx_palloc_block(pool, size);
}return ngx_palloc_large(pool, size);
}
pool是記憶體池的首位址,size是所需分配的記憶體大小。看完了**,是不是對pool與pool之間的關係比較模糊,別著急,pool與pool之間的關係是這樣子滴:
pool鍊錶間通過d結構體中的next相鏈結(紅線部分),而pool->current則指向目前可參與分配記憶體的起始pool(藍線),貌似只有第乙個pool的curernt有指向相應的pool,其他的pool好像在create時並未賦值,具體怎樣還要再讀**,這個疑問留待以後解決吧。
新建立pool並從pool中分配size空間的**如下:
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);
m = ngx_align_ptr(m, ngx_alignment);
new->d.last = m + size;
current = pool->current;
/*將pool鍊錶中從current所指向的pool開始到鍊錶中的最後乙個pool的failed值+1,代表該pool分配失敗的次數,如果該次數大於4,則current指向其下乙個pool節點。
*/ for (p = current; p->d.next; p = p->d.next)
}//將新pool節點插入鍊錶末尾
p->d.next = new;
pool->current = current ? current : new;
return m;
}
分配大塊記憶體的**如下所示:
static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
n = 0;
//試圖將p掛在原來已分配的large但large的alloc所指向的資料空間已被釋放的地方。
for (large = pool->large; large; large = large->next)
//只檢查large鍊錶的前三個節點,若前三個節點不可掛p,則跳出迴圈
if (n++ > 3)
}//從pool中分配large指標大小的空間(8位元組)
large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
if (large == null)
large->alloc = p;
//將新分配的large節點放在鍊錶的表頭,next指向原來的表頭節點,即從頭插入新節點。
large->next = pool->large;
pool->large = large;
return p;
}
第一次申請large空間的結果如下圖所示:
第二次申請large空間的結果為:
為何要把large節點插入為表頭的位置呢,個人推理該方法避免了沒插入乙個新節點必須遍歷真個large鍊錶的不必要開銷。
以下為加入將新的cleanup節點加入cleanup鍊錶的**:
ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
//從pool池中分配size大小的資料空間
if (size)
} else
c->handler = null;
//將新節點插入表頭中
c->next = p->cleanup;
p->cleanup = c;
ngx_log_debug1(ngx_log_debug_alloc, p->log, 0, "add cleanup: %p", c);
return c;
}
第一次加入cleanup的結果如下圖所示:
nginx記憶體管理方面的核心**已經解析完畢了,若有分析錯誤的地方望指正。
nginx 記憶體池
nginx對記憶體的管理由其內部的記憶體池實現,nginx在 src os unix ngx alloc.h c中定義了基本的記憶體分配操作,如malloc等。記憶體池部分的操作在 src core ngx palloc.h c 中實現。乙個基本的nginx記憶體池結構如下所示 由上圖可知,ngin...
C 記憶體管理 記憶體池
很多內容來自於網際網路,如有侵權,請告知。另外,從 收穫很多,在此表示感謝。我們寫程式經常需要 malloc 和 new 一塊記憶體出來,這些記憶體是在堆上進行分配的,在堆上分配的記憶體和在棧上分配的記憶體不同,可以長久的儲存。堆是什麼 可以把你的程序空間 想象成 4g 大小的記憶體 32 為機子上...
C 記憶體管理 記憶體池
引子 一 單獨類記憶體池 classa intget void operator new size t void operator delete void size t private a next static a freestore 指向可用首位址 static const int achunk...