首頁 後端開發 php教程 [nginx源碼分析]ngx記憶體池實現

[nginx源碼分析]ngx記憶體池實現

Aug 08, 2016 am 09:24 AM
current gt pool size

記憶體池函數:

ngx_create_pool
ngx_destroy_pool
ngx_reset_pool
ngx_palloc
ngx_pnalloc
ngx_palloc_block
ngx_palloc_large
ngx_pool_cleanup_add
登入後複製

記憶體池建立

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);//按照16字节对齐分配一块size大小内存
      if (p == NULL) {
          return NULL;
      }                                                                                                                                                              
  
      p->d.last = (u_char *) p + sizeof(ngx_pool_t);  //last指向数据部分开始(跳过header ngx_pool_t)结构
      p->d.end = (u_char *) p + size;                 //end指向末尾结构
      p->d.next = NULL;                               //next是对小块内存链表管理指针
      p->d.failed = 0;                                //此块内存分配失败次数
  
      size = size - sizeof(ngx_pool_t);               //去掉ngx_pool_t内存池的实际大小
      p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;//最大内存池节点大小为4095
  
      p->current = p;                                 //current指向p
      p->chain = NULL;
      p->large = NULL;
      p->cleanup = NULL;
      p->log = log;
  
      return p;
  }
登入後複製

其中初始化結構如下圖:

綠線表示是結構體成員,例如ngx_pool_data_t的成員包含表示指標指向的位址

1 max為建立size-sizeof(ngx_pool_t)和4095之間選取最小的

2 log在main中呼叫ngx_log_init所建立的ngx_log_t結構(即全域的ngx_log物件)

nginx實際上從這個記憶體池分配空間的起始位置從d.last開始,隨著記憶體池空間的對外分配,這個欄位的指向會後移,

記憶體池分配

void *
 ngx_palloc(ngx_pool_t *pool, size_t size)
 {  
     u_char      *m;
     ngx_pool_t  *p;       
 
     //如果申请的内存大小小于创建的内存池节点大小(当然是去掉ngx_pool_t后)
     if (size <= pool->max) {
 
         p = pool->current;
 
         do {
             m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);//首先对齐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);
 }
登入後複製
ngx_palloc()嘗試從pool記憶體池裡分配size大小的空間,這有兩種情況。

第一種如果分配的size小於ngx_pool_t.max(小塊分配,即代碼127-140),首先需要把last 16位對齊,如果申請還存在空間,那麼就用這一內存節點(即代碼130 )同時移動last指向分配後的位址,同時把申請的記憶體回傳給呼叫著,如果從current遍歷小塊記憶體節點都沒有可以分配的空間(即遍歷鍊錶一直到記憶體池節點next為空)。就需要分配記憶體池節點呼叫ngx_palloc_block(pool,size)

此函數主要分配一個記憶體池節點,然後把這個節點插入到鍊錶尾部,同時更新pool->current指針,更新演算法是遍歷鍊錶,如果發現這個節點已經分配失敗6次了,就把current指向下一個節點,如果所有節點都失敗6次以上,current指向新分配節點。

核心程式碼如下:

current = pool->current;//初始化
 
     for (p = current; p->d.next; p = p->d.next) {//遍历
         if (p->d.failed++ > 4) {//分配超过6次
             current = p->d.next;
         }
     }
 
     p->d.next = new;//插入新节点                                                                                                                          
 
     pool->current = current ? current : new;//更新current
登入後複製

第二種情況,分配大塊記憶體直接呼叫malloc分配,分配完,遍歷pool->large鍊錶,如果存在大塊記憶體池節點存在alloc為空,那麼就把新分配的記憶體掛到這個節點上,如果沒有這樣的節點,那就分配插入p->large的鍊錶頭部。
清除回呼函數

其中每個節點都是

 struct ngx_pool_cleanup_s {
      ngx_pool_cleanup_pt   handler;//回调handler
      void                 *data;	//回调函数参数
      ngx_pool_cleanup_t   *next;	//指向下一个节点
  };
登入後複製
ngx_pool_cleanup_t *      
 ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
 {
     ngx_pool_cleanup_t  *c;
    
     c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));//分配一个节点
     if (c == NULL) {      
         return NULL;
     }
 
     if (size) {
         c->data = ngx_palloc(p, size); 
         if (c->data == NULL) {
             return NULL;
         }
 
     } else {
         c->data = NULL;
     }
 
     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;                                                                                                                                                      
 }
登入後複製

以上就介紹了[nginx源碼分析]ngx內存池實現,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

華為GT3 Pro和GT4的差異是什麼? 華為GT3 Pro和GT4的差異是什麼? Dec 29, 2023 pm 02:27 PM

華為GT3 Pro和GT4的差異是什麼?

使用java的File.length()函數取得檔案的大小 使用java的File.length()函數取得檔案的大小 Jul 24, 2023 am 08:36 AM

使用java的File.length()函數取得檔案的大小

修復:截圖工具在 Windows 11 中不起作用 修復:截圖工具在 Windows 11 中不起作用 Aug 24, 2023 am 09:48 AM

修復:截圖工具在 Windows 11 中不起作用

如何修復無法連線到iPhone上的App Store錯誤 如何修復無法連線到iPhone上的App Store錯誤 Jul 29, 2023 am 08:22 AM

如何修復無法連線到iPhone上的App Store錯誤

php提交表单通过后,弹出的对话框怎样在当前页弹出,该如何解决 php提交表单通过后,弹出的对话框怎样在当前页弹出,该如何解决 Jun 13, 2016 am 10:23 AM

php提交表单通过后,弹出的对话框怎样在当前页弹出,该如何解决

使用TreeSet類別的size()方法取得樹集合中的元素數量 使用TreeSet類別的size()方法取得樹集合中的元素數量 Jul 24, 2023 am 11:05 AM

使用TreeSet類別的size()方法取得樹集合中的元素數量

watch4pro好還是gt好 watch4pro好還是gt好 Sep 26, 2023 pm 02:45 PM

watch4pro好還是gt好

如何使用 iPadOS 17.4 優化 iPad 電池壽命 如何使用 iPadOS 17.4 優化 iPad 電池壽命 Mar 21, 2024 pm 10:31 PM

如何使用 iPadOS 17.4 優化 iPad 電池壽命

See all articles