zoukankan      html  css  js  c++  java
  • haproxy内存管理-free_list原理

    haproxy的内存管理中,通过pool_head->free_list,存储空闲内存块,free_list是个二级指针,却把空闲内存块都串了起来,没有用next,pre之类的指针。怎么实现的?着实思考了半个小时才明白。
    pool_head结构:

    struct pool_head {
    	void **free_list;   /* 空闲链表 */
    	struct list list;	/* 双向链表,链接每种类型的内存池 */
    	unsigned int used;	/* 使用了多少内存块 */
    	unsigned int allocated;	/* 分配了多少内存块 */
    	unsigned int limit;	/* 内存块上限 */
    	unsigned int minavail;	/* 最少保留几个,回收时不会全部回收 */
    	unsigned int size;	/* 内存块大小 */
    	unsigned int flags;	/* 能否共享,类型不同,但大小相同的,能否共享一个pool_head */
    	unsigned int users;	/* 内存池有几个使用者 */
    	char name[12];		/* 内存池名称 */
    };
    

    可知,free_list是个二级指针,二级指针是指向指针的指针,对二级指针进行*操作,会得到一级指针指向的地址。

    free_list操作

    #define pool_alloc2(pool)                                     
    ({                                                            
            void *__p;                                            
            if ((__p = pool->free_list) == NULL)                  
                    __p = pool_refill_alloc(pool);                
            else {                                                
                    pool->free_list = *(void **)pool->free_list;  
                    pool->used++;                                 
            }                                                     
            __p;                                                  
    })
    

    当free_list为NULL时,调用pool_refill_alloc申请内存,看到这里的时候有点懵逼,这样的话,一直申请内存,pool->free_list还是一直是NULL,就算不是NULL,pool->free_list = *(void **)pool->free_list又是什么鬼?
    后面看内存回收才明了。

    #define pool_free2(pool, ptr)                           
    ({                                                      
            *(void **)ptr = (void *)pool->free_list;        
            pool->free_list = (void *)ptr;                  
            pool->used--;                                   
            pool_gc2_ifneed(pool);                          
    })
    

    下面这句,往*ptr,即申请的内存块(取名为buff0)中写入pool->free_list的值,pool->free_list是个二级指针,所以内存块的前32位就写入了一个地址,这个地址可能是NULL,也可能指向下一个内存块。

    *(void **)ptr = (void *)pool->free_list;
    

    然后,

     pool->free_list = (void *)ptr;
    

    pool->free_list等于了ptr,所以,现在pool->free_list指向了buff0。
    所以,在申请内存中,

    pool->free_list = *(void **)pool->free_list;
    

    对pool->free_list进行*操作,因其是二级指针,所以取到的是第一块buffer的前32字节,而前32字节存的是第二块buffer的地址,所以free_list变成指向第二块buffer,嗯,第一块已经分配出去了,在if的判断语句里有

     if ((__p = pool->free_list) == NULL) 
    

    所以此时__p指向了第一块内存。因为p是一级指针,所以在使用*p的时候,会取到整个内存块。

    过程图解

    总结

    1. 对二级指针进行*操作,会取到32位地址
    2. buffer的前32位是地址
    3. 同一个地址,都进行*操作,会因类型不同而取到不同值,这就是《CSAPP》说的,信息是位+上下文。
    4. 羡慕指针玩得6的人。
  • 相关阅读:
    JavaScript的性能优化:加载和执行
    JS获取图片的原始尺寸
    深入理解js构造函数
    Revit二次开发 获取缩略图
    WPF listbox分页
    WPF ListBox 图片显示及分页
    Revit禁用RibbonPanel
    C# excel 单元格居中
    WPF TreeView
    WPF ListView绑定数据
  • 原文地址:https://www.cnblogs.com/shenlinken/p/6919592.html
Copyright © 2011-2022 走看看