zoukankan      html  css  js  c++  java
  • NGINX原理分析 之 SLAB分配机制 (转)

    转自:http://blog.csdn.net/qifengzou/article/details/11678115

    作者:邹祁峰 
    邮箱:Qifeng.zou.job@gmail.com
    博客:http://blog.csdn.net/qifengzou
    日期:2013.09.15 23:19
    转载请注明来自"祁峰"的CSDN博客


    1 引言

        众所周知,操作系统使用伙伴系统管理内存,不仅会造成大量的内存碎片,同时处理效率也较低下。SLAB是一种内存管理机制,其拥有较高的处理效率,同时也有效的避免内存碎片的产生,其核心思想是预分配。其按照SIZE对内存进行分类管理的,当申请一块大小为SIZE的内存时,分配器就从SIZE集合中分配一个内存块(BLOCK)出去,当释放一个大小为SIZE的内存时,则将该内存块放回到原有集合,而不是释放给操作系统。当又要申请相同大小的内存时,可以复用之前被回收的内存块(BLOCK),从而避免了内存碎片的产生。[注:因SLAB处理过程的细节较多,在此只是做一个原理上的讲解]


    2 总体结构

    图1 SLAB内存结构


    3 处理流程
        如图1中所示:SLAB管理机制将内存大体上分为SLAB头、SLOT数组、PAGES数组、可分配空间、被浪费空间等模块进行分别管理,其中各模块的功能和作用:
    SLAB头:包含SLAB管理的汇总信息,如最小分配单元(min_size)、最小分配单元对应的位移(min_shift)、页数组地址(pages)、空闲页链表(free)、可分配空间的起始地址(start)、内存块结束地址(end)等等信息(如代码1所示),在内存的管理过程中,内存的分配、回收、定位等等操作都依赖于这些数据。
    SLOT数组:SLOT数组各成员分别负责固定大小的内存块(BLOCK)的分配和回收。在nginx中SLOT[0]~SLOT[7]分别负责区间在[1~8]、[9~16]、[17~32]、[33~64]、[65~128]、[129~256]、[257~512]、[513~1024]字节大小内存的分配,但为方便内存块(BLOCK)的分配和回收,每个内存块(BLOCK)的大小为各区间的上限(8、16、32、64、128、256、512、1024)。比如说:假如应用进程请求申请5个字节的空间,因5处在[1~8]的区间内,因此由SLOT[0]负责该内存的分配,但区间[1~8]的上限为8,因此即使申请5个字节,却依然分配8字节给应用进程。以此类推:假如申请12字节,12处于区间[9~16]之间,取上限16,因此由SLOT[1]分配16个字节给应用进程;假如申请50字节,50处于区间[33~64]之间,取上限64,因此由SLOT[2]分配64个字节给应用进程;假如申请84字节,84处于区间[65~128]之间,取上限128,因此由SLOT[3]分配128个字节;...;假如申请722字节,722处于区间[513~1024]之间,取上限1024,因此由SLOT[7]分配1024字节。
    PAGES数组:PAGES数组各成员分别负责可分配空间中各页的查询、分配和回收,其处理流程可参考3.2节的说明。
    可分配空间:SLAB在逻辑上将可分配空间划分成M个内存页,每页大小为4K。每页内存与PAGES数组成员一一对应,由PAGES数组各成员负责各内存页的分配和回收。
    被浪费空间:按照每页4K的大小对空间进行划分时,满足4K的空间,将作为可分配空间被PAGES数组进行管理,而最后剩余的不足4K的内存将会被舍弃,也就是被浪费了!
    3.1 初始化流程

         初始化阶段主要完成对SLOT头、SLOT数组、PAGES数组、可分配空间和被浪费空间的区域分化,各区域的划分可参考图1和各模块功能的说明。nginx中slab结构体如下所示:


    [html] view plaincopyprint?在CODE上查看代码片派生到我的代码片
    typedef struct {  
        size_t            min_size;     /* 最小分配单元 */  
        size_t            min_shift;    /* 最小分配单元对应的位移 */  
      
        ngx_slab_page_t  *pages;        /* 页数组 */  
        ngx_slab_page_t   free;         /* 空闲页链表 */  
      
        u_char           *start;        /* 可分配空间的起始地址 */  
        u_char           *end;          /* 内存块的结束地址 */  
      
        ...                             /* 其他变量成员(省略) */  
    }ngx_slab_pool_t  

    typedef struct {
        size_t            min_size;     /* 最小分配单元 */
        size_t            min_shift;    /* 最小分配单元对应的位移 */
    
        ngx_slab_page_t  *pages;        /* 页数组 */
        ngx_slab_page_t   free;         /* 空闲页链表 */
    
        u_char           *start;        /* 可分配空间的起始地址 */
        u_char           *end;          /* 内存块的结束地址 */
    
        ...                             /* 其他变量成员(省略) */
    }ngx_slab_pool_t


     

    代码1 SLAB头部结构体


    3.2 页的管理
    3.2.1 页的分配

    1)分配之前

        在SLAB初始化之后,所有页可以看成是一个连续的整体,其内存结构如下图所示:

    图2 页的结构(分配之前)

    2)申请一页

        当申请一页时,则将pages[0]从free链表中分离出去,如下图所示:

    图3 页的结构(申请一页)

    3)申请二页

        当再申请二页时,则将page[3]和pages[4]作为一个整体从free链表中分离出去,如下图所示:

    图4 页的结构(申请二页)


    3.2.2 页的回收

    1)回收一页

        当页被回收时,被回收的页并不会和未被分配的页进行合并,而是通过链表串联起来,如下图所示:

    图5 页的结构(回收一页)

    2)回收二页

        当页被回收时,被回收的页并不会和未被分配的页进行合并,而是通过链表串联起来,如下图所示:

    图6 页的结构(回收二页)


    3.4 SLOT的管理

        SLOT数组的作用可以参考第三章开头的阐述。SLOT数组各成员相当于链表头,在SLOT的分配和回收过程中,通过链表来组织用于分配各SIZE(1~1024)的PAGE。如,在某时刻,可能存在如下状态:

    图7  SLOT和PAGES的关系


    3.4.1 页的管理

    1)初始状态

        在SLAB初始化后,slot链表头的下一个节点都为NULL,如下图所示:

    图8 SLOT初始状态

    2)添加一页

        SLOT[2]负责32(17~32)字节空间的分配和回收,假设现申请分配24字节(17~32之间)的空间,因此将从slot[2]中分配。但在初始状态下slot[2]的下一页为NULL,因此需要向页管理模块申请一页pages[x]内存,再将该页加入到slot[2]的链表中,添加之后的内存结构如下图所示:

    图9 slot[2]增加一页

    3)暂离链表

       SLOT[2]中的每一页有128(4K/32=128)个单元,当一页分配了128次时,表示该页可分配单元分配完毕,此时该页将会暂时从链表中剔除出去,以防止下次申请时,做无效的遍历。如下图所示:

    图10 slot[2]第一页被使用完

    4)再添一页

        当再次申请17~32字节时,此时slot[2]的后续链表为空,因此需要再次向页管理申请一页pages[y]内存,再将该页加入到slot[2]的链表中,如下图所示。如果该页又被分配完,则进行3)的处理。

    图11 slot[2]再添一页

    5)重入链表

          当所有单元被用完的页pages[x]中的一个单元被回收时,页pages[x]中将有1个单元可以再次被分配使用,此时应该将pages[x]重新加入到slot[2]的链表中,以便下次分配时可以从页pages[x]中进行查找。此时内存组织形式如下图所示:

    图12 页pages[x]重入链表

    6)回收整页

        当页pages[x]所有单元被释放后,则该页将会被全部回收:该页将从slot[2]的链表中被剔除,并将页pages[x]重新加入到free链表。此时的内存结构图如下图所示:

    图13 回收页pages[x]


    3.4.2 SLOT的分配

    1)页内结构

        被加入到SLOT数组链表的页在逻辑上划分为很多的内存单元,每一小内存单元的使用情况是通过位图进行标记的,1表示被占用,0表示未被占用。如:第20位bit的值为1时,表示第20个内存单元被占用。假如此SLOT链表的PAGE正好可以划分为32块,则其逻辑组织结构如下图所示:

    图14 PAGE内结构

    2)分配单元

        假如此时在SLOT[s]链表的页中连续申请4个内存单元,则其前4个内存单元将首先被占用,则此时的位图结构如下图所示:

    图15 分配单元

    3)释放单元

        假如此时释放SLOT[s]链表页中第3个内存单元,则此时的位图结构如下图所示:

    图16 释放单元

  • 相关阅读:
    Postman使用教程
    CAD和ArcGIS转换 矢量配准
    SAP CRM Advanced search和Simple search里Max hit表现行为的差异
    SAP CRM Product simple search的启用步骤
    如何快速定位SAP CRM订单应用(Order Application)错误消息抛出的准确位置
    如何动态修改SAP CRM WebClient UI表格栏的宽度
    如何在SAP CRM WebClient UI里创建web service并使用ABAP消费
    如何处理SAP CRM Web Service错误
    如何使用SAP CRM WebClient UI实现一个类似新浪微博的字数统计器
    如何开启SAP CRM基于WORD模板创建附件的功能
  • 原文地址:https://www.cnblogs.com/ddwapple/p/4607211.html
Copyright © 2011-2022 走看看