Linux(服務器編程):36---C/C++內存池設計(仿Nginx內存池設計)

一、內存池概述

  • 服務器會頻繁地對內存進行申請和釋放,頻繁地操作將帶來如下的缺點:
    • 服務器性能降低,因爲需要頻繁地申請和釋放內存
    • 內存碎片化多
    • 等等......
  • 市場上開源的比較好用的內存池有:
    • tcmalloc:MySQL使用的
    • jemalloc:Tomcat使用的
    • Nginx也有一套自己的內存池(本文就是仿照Nginx的內存池設計的)

二、內存池設計

  • 因爲內存頁的大小爲4K,因此在設計內存池的時候,我們將認爲:
    • <4k的內存:稱爲小內存塊
    • >4K的內存:稱爲大內存快

struct mp_large_s(大內存塊結構)

  • 當我們申請的內存大於4K時,就會申請一個大的內存塊,這個結構體就是大內存結構
  • 該結構不是真正存儲內存的,真正的內存是由其alloc成員所指向的
  • 如上結構圖所示(藍色部分):
    • alloc:指向真正的大內存塊地址
    • next:指向下一個struct mp_large_s結構的指針
//大內存塊節點
struct mp_large_s {
    void *alloc;             //指向該大內存快的實際存儲區域
    struct mp_large_s *next; //指向下一塊大內存快
};

struct mp_node_s(大內存塊結構)

  • 當我們申請的內存小於4K時,就會申請一個小的內存塊,這個結構體就是小內存結構
  • 與struct mp_large_s結構一樣,該結構不是真正存儲內存的,真正的內存是在結構後面的data區域存儲的
  • 如上結構圖所示(藍色部分):
    • last:指向後面data區域中可用內存的起始地址
    • end:指向後面data區域最後的指針
    • next:指向下一個struct mp_node_s結構的指針
    • failed:表示當前內存塊是否停止使用
//小內存塊節點
struct mp_node_s {
    unsigned char *last;     //後面數據存儲區域中可用區域的起點
    unsigned char *end;      //後面數據存儲區域的終點
    
    struct mp_node_s *next;  //指向下一塊小內存塊
    
    int failed;              //該內存塊是否不再使用
};

struct mp_pool_s(內存池)

  • 該結構是內存池的真正結構,我們操作內存池時就是操作這個結構
  • 如上結構圖所示(藍色部分):
    • max:區別大內存塊與小內存塊的界值,上面我們提到過了,我們本案例以4K爲例
    • current:指向小內存塊鏈表的起點
    • large:指向大內存塊鏈表的起點
    • head[0]:柔性數組,struct mp_node_s head[0]相當於struct mp_node_s *head。用來指向於current鏈表中的第一個struct mp_node_s節點,通過這個成員可以方便的操作current鏈表
//內存池,管理者所有的內存塊
struct mp_pool_s {
    //區別大內存塊與小內存塊的界值: <max的用struct mp_node_s表示, >max的用struct mp_large_s表示
    int max;

    struct mp_node_s  *current; //管理小內存塊的鏈表起點
    struct mp_large_s *large;   //管理大內存快的鏈表起點

    //柔型數組: head[0]指向current鏈表第1個節點, head[1]指向current鏈表第2個節點...以此類推
    //用這個數組來操作每個mp_node_s節點相關指標(比如更改last等),不需要再去遍歷
    struct mp_node_s head[0];
};

三、內存池接口設計

  • 下面是內存池的相關接口

四、代碼實現

五、運行效果

  • 該代碼正在修正,最近幾天完成
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章