Heim > Artikel > Backend-Entwicklung > Nginx erweiterte Datenstruktur-Quellcode-Analyse (4) -----Speicherpool
Die Verwendung eines Speicherpools bringt Nginx viele Vorteile, wie z. B. eine bequemere Speichernutzung, eine Vereinfachung des Logikcodes und eine Verbesserung der Programmleistung.
Einige wichtige Wissenspunkte sind unten aufgeführt:
(1) Wenn die Funktion ngx_palloc() versucht, Speicher der Größe size from zuzuweisen Speicher: Es gibt zwei Situationen, in denen die Größe kleiner als pool->max ist. Dies wird als kleine Speicherzuweisung bezeichnet. Wenn der aktuelle Speicherpoolknoten kleiner als die Größe ist, beantragen Sie einen neuen Speicherpoolknoten derselben Größe. und beginnen Sie dann mit diesem neuen Speicherpool. Der Knoten weist Speicherplatz der Größe size zu. Wenn die Größe größer als pool->max ist, wird ein großer Speicherblock zugewiesen, und die zu diesem Zeitpunkt aufgerufene Funktion bezieht sich direkt auf einen großen Speicherblock vom Betriebssystem.
(2) Die Anwendung für einen kleinen Speicherblock wird am hinteren Knoten der verknüpften Liste eingefügt, während der neue große Speicherblock am Anfang der verknüpften Liste eingefügt wird .
(3) Nginx bietet nur die Freigabe großer Speicherblöcke und keine Freigabe kleiner Speicherblöcke, was bedeutet, dass der aus dem Speicherpool zugewiesene Speicher nicht freigegeben wird Zurück in den Speicherpool zurückgeführt, und erst wenn der gesamte Speicherpool zerstört ist, wird der Speicher wieder in den Systemspeicher zurückgeführt.
(4) Das aktuelle Feld in ngx_pool_t: Dieses Feld zeichnet den Startknoten auf, von dem aus Speicher aus dem Speicherpool zugewiesen wird. Nginx legt fest, dass die Gesamtzahl der Zuordnungsfehler für einen Speicher Knoten ist größer oder gleich 6-mal, der Strom zeigt auf den nächsten Speicherknoten.
(5) Warum sollte der maximale Wert des Pool->max-Felds auf eine Seite des Speichers begrenzt sein? Der Grund dafür ist, dass die Zuweisung von Caching nur dann erforderlich ist, wenn der Speicherplatz weniger als eine Seite beträgt. Andernfalls ist es besser, die Systemschnittstelle malloc() direkt auf das Betriebssystem anzuwenden.
Definition jeder Struktur:
//大块内存管理结构 struct ngx_pool_large_s { ngx_pool_large_t *next; //连接下一个大内存管理 void *alloc; //申请的大内存地址 }; //内存池中数据管理 typedef struct { u_char *last; //可用内存的起始地址 u_char *end; //可用内存的末尾地址 ngx_pool_t *next; //指向下一个内存池节点 ngx_uint_t failed; //申请时,失败的次数 } ngx_pool_data_t; //内存池 struct ngx_pool_s { ngx_pool_data_t d; //存放数据 size_t max; //存放数据的可用内存大小,最大为1页 ngx_pool_t *current; //指向分配内存的内存池 ngx_chain_t *chain; ngx_pool_large_t *large; //连接大内存管理结构 ngx_pool_cleanup_t *cleanup; //清理对象头 ngx_log_t *log; };Speicherpool-Initialisierung :
//创建一个size的内存池 ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log) { ngx_pool_t *p; p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log); //以对齐的方式来申请size字节内存 if (p == NULL) { return NULL; } p->d.last = (u_char *) p + sizeof(ngx_pool_t); //指向可用的内存起始地址 p->d.end = (u_char *) p + size; //指向可用内存的末尾地址 p->d.next = NULL; //初始时,下一个可用内存为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; }Zerstörung und Zurücksetzen des Speicherpools:
//销毁内存池 void ngx_destroy_pool(ngx_pool_t *pool) { ngx_pool_t *p, *n; ngx_pool_large_t *l; ngx_pool_cleanup_t *c; //运行清理对象的handler for (c = pool->cleanup; c; c = c->next) { if (c->handler) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "run cleanup: %p", c); c->handler(c->data); } } //释放大内存 for (l = pool->large; l; l = l->next) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); if (l->alloc) { ngx_free(l->alloc); //使用free释放malloc申请的内存 } } #if (NGX_DEBUG) /* * we could allocate the pool->log from this pool * so we cannot use this log while free()ing the pool */ for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p, unused: %uz", p, p->d.end - p->d.last); if (n == NULL) { break; } } #endif //释放每一个申请的内存池对象ngx_pool_t for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_free(p); if (n == NULL) { break; } } } //重设内存池 void ngx_reset_pool(ngx_pool_t *pool) { ngx_pool_t *p; ngx_pool_large_t *l; //释放大内存 for (l = pool->large; l; l = l->next) { if (l->alloc) { ngx_free(l->alloc); } } //内存池对象,仅仅改变last的指针位置 for (p = pool; p; p = p->d.next) { p->d.last = (u_char *) p + sizeof(ngx_pool_t); //导致所有的内存池对象的可用内存的起始地址偏移都一样 p->d.failed = 0; } pool->current = pool; pool->chain = NULL; pool->large = NULL; }Speicher zuweisen:
//分配内存(地址对齐) void * ngx_palloc(ngx_pool_t *pool, size_t size) { u_char *m; ngx_pool_t *p; if (size <= pool->max) { //小内存申请时,以size为标准 p = pool->current; do { m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); //首先将d.last地址对齐 if ((size_t) (p->d.end - m) >= size) { //可用的内存大于要申请的内存 p->d.last = m + size; //直接更新d.last return m; //直接返回 } p = p->d.next; //否则找下一个可用的内存池对象 } while (p); //没有找到,则要申请新的内存池对象 return ngx_palloc_block(pool, size); } return ngx_palloc_large(pool, size); //大内存申请处理 } //分配内存(地址可以不对齐) void * ngx_pnalloc(ngx_pool_t *pool, size_t size) { u_char *m; ngx_pool_t *p; if (size <= pool->max) { //小内存 p = pool->current; do { m = p->d.last; if ((size_t) (p->d.end - m) >= size) { p->d.last = m + size; return m; } p = p->d.next; } while (p); return ngx_palloc_block(pool, size); //申请新内存池对象 } return ngx_palloc_large(pool, size); //大内存 }Speicher in kleinen Blöcken zuweisen:
//申请新的内存池对象 static void * ngx_palloc_block(ngx_pool_t *pool, size_t size) { u_char *m; size_t psize; ngx_pool_t *p, *new; psize = (size_t) (pool->d.end - (u_char *) pool); //申请内存的总大小 m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log); //对齐方式申请内存 if (m == NULL) { return NULL; } new = (ngx_pool_t *) m; //新的内存 new->d.end = m + psize; //可用的内存的最后地址 new->d.next = NULL; new->d.failed = 0; m += sizeof(ngx_pool_data_t); //只有一个ngx_pool_data_t,节省了ngx_pool_t的其余开销 m = ngx_align_ptr(m, NGX_ALIGNMENT); new->d.last = m + size; //可用的内存的起始地址 //如果当前申请内存的失败的次数已经有5次了,第6次,current将会指向新的内存池对象 for (p = pool->current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { pool->current = p->d.next; } } p->d.next = new; //连接刚刚申请的内存池对象 return m; }Speicherzuweisung blockieren
//大内存申请处理 static void * ngx_palloc_large(ngx_pool_t *pool, size_t size) { void *p; ngx_uint_t n; ngx_pool_large_t *large; p = ngx_alloc(size, pool->log); //直接malloc申请内存 if (p == NULL) { return NULL; } n = 0; for (large = pool->large; large; large = large->next) { if (large->alloc == NULL) { //如果有内存被释放了,可重用 large->alloc = p; return p; } if (n++ > 3) { //但是只找4次,第5次直接break,创建大内存的管理结构 break; } } large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); //从内存池对象申请内存 if (large == NULL) { ngx_free(p); return NULL; } large->alloc = p; //指向申请的大内存 //插入large的头 large->next = pool->large; pool->large = large; return p; }Direkte Speicherzuweisung:
//不管内存大小多大,向操作系统申请内存 void * ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment) { void *p; ngx_pool_large_t *large; p = ngx_memalign(alignment, size, pool->log); //申请的内存 if (p == NULL) { return NULL; } large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); //申请一个大内存管理结构 if (large == NULL) { ngx_free(p); return NULL; } //放入到内存池ngx_pool_t中管理 large->alloc = p; //指向申请的内存 //插入到头部 large->next = pool->large; pool->large = large; return p; }Speicher freigeben:
//释放内存 ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p) { ngx_pool_large_t *l; //只释放大内存 for (l = pool->large; l; l = l->next) { if (p == l->alloc) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); ngx_free(l->alloc); l->alloc = NULL; //置为空 return NGX_OK; } } return NGX_DECLINED; }
Copyright-Erklärung: Dieser Artikel ist ein Originalartikel des Bloggers und darf ohne das nicht reproduziert werden Erlaubnis des Bloggers.
Das Obige stellt die erweiterte Nginx-Datenstruktur-Quellcode-Analyse vor (4) ----- Speicherpool, einschließlich Aspekten des Inhalts. Ich hoffe, dass es für Freunde hilfreich sein wird, die an PHP-Tutorials interessiert sind.