精华内容
下载资源
问答
  • stl内存池怎么实现的

    2018-08-15 15:47:36
    C++技术问题总结-第8篇 STL内存池怎么实现的  STL内存池机制,使用双层级配置器。第一级採malloc、free,第二级视情况採不同策略。   这样的机制从heap中要空间,能够解决内存碎片问题。 1.内存申请流程...

    C++技术问题总结-第8篇 STL内存池是怎么实现的

        STL内存池机制,使用双层级配置器。第一级採用malloc、free,第二级视情况採用不同策略。

     

    这样的机制从heap中要空间,能够解决内存碎片问题。


    1.内存申请流程图
        简要流程图例如以下。


    2.第二级配置器说明
        第二级配置器目的解决小型区块造成的内存碎片问题。

     


        使用自由链表(free-list)技巧。主动将不论什么小额区块的内存需求量上调至8的倍数。如需求30,则上调至32。
        free-list节点结构
        union obj
        {
            union obj* free_list_link;
            char client_data[];
        };
        有16个free-lists。各自管理大小分别为8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytes的小额区块。
        申请流程例如以下。

        释放流程例如以下。

    展开全文
  • STL内存池机制,使用双层级配置器。第一级採malloc、free,第二级视情况採不同策略。这样的机制从heap中要空间,能够解决内存碎片问题。 1.内存申请流程图 简要流程图例如以下。 2.第二级配置器说明 ...
        STL内存池机制,使用双层级配置器。第一级採用malloc、free,第二级视情况採用不同策略。

    这样的机制从heap中要空间,能够解决内存碎片问题。


    1.内存申请流程图
        简要流程图例如以下。

    2.第二级配置器说明
        第二级配置器目的解决小型区块造成的内存碎片问题。


        使用自由链表(free-list)技巧。主动将不论什么小额区块的内存需求量上调至8的倍数。如需求30,则上调至32。
        free-list节点结构
        union obj
        {
            union obj* free_list_link;
            char client_data[];
        };
        有16个free-lists。各自管理大小分别为8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytes的小额区块。
        申请流程例如以下。

        释放流程例如以下。


    转载于:https://www.cnblogs.com/zsychanpin/p/6936810.html

    展开全文
  • STL源码分析之内存池

    2018-12-10 08:42:27
    上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池怎么保存空间的, 是不是内存池真的有不完的内存, 本节我们就具体来分析一下 ...

    STL源码分析之内存池

    前言

    上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池是怎么保存空间的, 是不是内存池真的有用不完的内存, 本节我们就具体来分析一下

    内存池

    static data template的初始化

    template <bool threads, int inst>
    char *__default_alloc_template<threads, inst>::start_free = 0;  // 内存池的首地址
    template <bool threads, int inst>
    char *__default_alloc_template<threads, inst>::end_free = 0;    // 内存池的结束地址
    template <bool threads, int inst>
    size_t __default_alloc_template<threads, inst>::heap_size = 0;  // 多次调用内存池, 就会更多的是给链表分配内存, 这就是一个增量.

    这里代码注释写的很清楚了, 我就提取出来分析一下吧

    1. 内存池的大小大于需要的空间, 直接返回起始地址(nobjs默认设置为20, 所以每次调用都会给链表额外的19个内存块)
    2. 内存池的内存不足以马上分配那么多内存, 但是还能满足分配一个即以上的大小, 那就全部分配出去
    3. 如果一个对象的大小都已经提供不了了, 先将零碎的内存块给一个小内存的链表来保存, 然后就准备调用malloc申请40块+额外大小的内存块(额外内存块就由heap_size决定), 如果申请失败跳转到步骤4, 成功跳转到步骤6
    4. 充分利用更大内存的链表, 通过递归来调用他们的内存块
    5. 如果还是没有内存块, 直接调用一级配置器来申请内存, 还是失败就抛出异常, 成功申请就继续执行
    6. 重新修改内存起始地址和结束地址为当前申请的地址块, 重新调用chunk_alloc分配内存
    // 内存池
    template <bool threads, int inst>
    char* __default_alloc_template<threads, inst>::chunk_alloc(size_t size, int& nobjs)
    {
        char * result;
        size_t total_bytes = size * nobjs;            // 链表需要申请的内存大小
        size_t bytes_left = end_free - start_free;    // 内存池里面总共还有多少内存空间
    
          // 内存池的大小大于需要的空间, 直接返回起始地址
        if (bytes_left >= total_bytes) 
        {
            result = start_free;
            start_free += total_bytes;  // 内存池的首地址往后移
            return(result);
        }
        // 内存池的内存不足以马上分配那么多内存, 但是还能满足分配一个即以上的大小, 那就按对齐方式全部分配出去
        else if (bytes_left >= size) 
        {
            nobjs = bytes_left/size;
            total_bytes = size * nobjs;
            result = start_free;
            start_free += total_bytes;  // 内存池的首地址往后移
            return(result);
        } 
        else 
        { 
            // 如果一个对象的大小都已经提供不了了, 那就准备调用malloc申请两倍+额外大小的内存
            size_t bytes_to_get = 2 * total_bytes + ROUND_UP(heap_size >> 4);
            // Try to make use of the left-over piece.
            // 内存池还剩下的零头内存分给给其他能利用的链表, 也就是绝不浪费一点.
            if (bytes_left > 0) 
            {
                // 链表指向申请内存的地址
                obj * __VOLATILE * my_free_list = free_list + FREELIST_INDEX(bytes_left);
                ((obj *)start_free) -> free_list_link = *my_free_list;
                *my_free_list = (obj *)start_free;
            }
            start_free = (char *)malloc(bytes_to_get);
            // 内存不足了
            if (0 == start_free) 
            {
                int i;
                obj * __VOLATILE * my_free_list, *p;
                // 充分利用剩余链表的内存, 通过递归来申请
                for (i = size; i <= __MAX_BYTES; i += __ALIGN) 
                {   
                    my_free_list = free_list + FREELIST_INDEX(i);
                    p = *my_free_list;
                    if (0 != p) 
                    {
                        *my_free_list = p -> free_list_link;
                        start_free = (char *)p;
                        end_free = start_free + i;
                        return(chunk_alloc(size, nobjs));
                    }
                }
                // 如果一点内存都没有了的话, 就只有调用一级配置器来申请内存了, 并且用户没有设置处理例程就抛出异常
                end_free = 0;   // In case of exception.
                start_free = (char *)malloc_alloc::allocate(bytes_to_get);
            }
                // 申请内存成功后重新修改内存起始地址和结束地址, 重新调用chunk_alloc分配内存
                heap_size += bytes_to_get;
                end_free = start_free + bytes_to_get;
                return(chunk_alloc(size, nobjs));
        }   
    }

    总结

    内存池的存在就是为了能快速的提供我们做需要的内存并且保存多余的空间, 让STL分配空间不再每次都进行malloc和free的操作, 效率又很有保障. 有时用户申请的块更小, 我们也能充分的利用起来. 唯一可能不足的是我们每次只申请char个大小, 但是内存池获得的确是8字节的大小.

    展开全文
  • Nginx 内存池管理

    2016-10-13 10:34:32
    Nginx内存池的设计十分巧妙, 可以研究一下, 以后再写代码的时候可以上。其具体分配的每个内存块的结构如下图。那么怎么构造出这样的结构呢? 看下下面的数据结构再说。它有两个最为重要的数据结构,如下: 其中...

    主要涉及的两个文件为ngx_palloc ngx_alloc
    Nginx内存池的设计十分巧妙, 可以研究一下, 以后再写代码的时候可以用上。其具体分配的每个内存块的结构如下图。那么怎么构造出这样的结构呢? 看下下面的数据结构再说。

    这里写图片描述

    它有两个最为重要的数据结构,如下:
    其中ngx_pool_s即所谓的内存池, 他数据的具体细节可以参考注释:

    typedef struct {
        u_char               *last;//表示当前可以写的位置,当这个ngx_pool_s(即内存块)被用尽了,则end == last
        u_char               *end; //表示这个当前内存块最后的位置
        ngx_pool_t           *next;//用来寻找下个内存块,当这是最后一个内存块,则next == NULL
        ngx_uint_t            failed;// 意义不大的参数,可以忽略
    } ngx_pool_data_t;
    
    
    struct ngx_pool_s {
        ngx_pool_data_t       d; //d的数据结构如上,用来找当前可以写的位置,
        size_t                max;//表示当前内存最大能分配到多大
        ngx_pool_t           *current;// 用来表示当前内存块访问到哪个了
        ngx_chain_t          *chain;// 与基本内存无关,后面阐述,
        ngx_pool_large_t     *large;// 是个链表,存储large的内存
        ngx_pool_cleanup_t   *cleanup;// 与基本内存无关,后面阐述,
    };
    

    可能对上述的数据结构还不太了解,那么就从如何创建ngx_pool_s这个结构体的变量和创建的过程来说吧。

     ngx_pool_t *pool = ngx_create_pool(1024, log);

    看如下代码, 只有第一个参数1024管用,后面的log可以忽略,表示创建一个每个内存块size为1024的。
    至于创建的过程看下述代码,细节如下

    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大小的空间,并且将void *转为ngx_pool_t *,这样这块内存空间的头被ngx_pool_t占用,
        if (p == NULL) {
            return NULL;
        }
    
        p->d.last = (u_char *) p + sizeof(ngx_pool_t);//现在pool指向的地址更新,注意要避过ngx_pool_t的头
        p->d.end = (u_char *) p + size;// 现在pool的地址空间的尾地址
        p->d.next = NULL;//因为刚申请create pool后面没有后续的空间,所以为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;//当后面如果要从pool内申请的空间小于p->max就分配小空间,即本文所述,
    
        p->current = p;// 更新pool指向哪个内存块
        p->chain = NULL;
        p->large = NULL;
        p->cleanup = NULL;
        p->log = log;
    
        return p;
    }

    那么如何从pool内申请内存呢?
    由下述三个函数完成。第一个函数前面已经讲了,没啥特别的,第二第三个函数细节请看注释吧

    void *
    ngx_palloc(ngx_pool_t *pool, size_t size)
    {
    #if !(NGX_DEBUG_PALLOC)
        if (size <= pool->max) {
            return ngx_palloc_small(pool, size, 1);
        }
    #endif
    
        return ngx_palloc_large(pool, size);
    }
    static ngx_inline void *
    ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
    {
        u_char      *m;
        ngx_pool_t  *p;
    
        p = pool->current;
    
        do {
            m = p->d.last;//找到当前pool的最后的地址
            if (align) {
                m = ngx_align_ptr(m, NGX_ALIGNMENT);//align 一下指针,让它是NGX_ALIGNMENT的倍数
            }
    
            if ((size_t) (p->d.end - m) >= size) {
            //判断当前pool剩余空间是不是满足,
            //如果满足,就更新pool当前指向的地址,并且返回这块地址,
                p->d.last = m + size;
                return m;
    
            }
    //如果找不到,找下一块pool
            p = p->d.next;
    
        } while (p);//直到最后一个pool
    
    
        return ngx_palloc_block(pool, size);
        //最后还是没找到, 就ngx_palloc_block(pool, size)
    }
    
    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);
    //计算每次pool该分配的大小,即size
        m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);// 分配内存,且align一下指针,让它是NGX_POOL_ALIGNMENT的倍数
        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);
        m = ngx_align_ptr(m, NGX_ALIGNMENT);
        new->d.last = m + size;//更新一下现在内存指到哪了?
    
        for (p = pool->current; p->d.next; p = p->d.next) {
            if (p->d.failed++ > 4) {
                pool->current = p->d.next;//如果当前p->d.failed++就更新一下pool->current 变成它的next,下次找内存就从这边还是寻找。
            }
        }
    
        p->d.next = new;//把新分配的pool挂在后面
    
        return m;
    }
    

    前面说了 alloc small的内存,但是没有说大的内存,说说alloc large的内存吧

    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);// 先分配size大小的空间
        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) {
                break;
            }
        }
    
        large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
        //从小内存中找到ngx_pool_large_t空间大小存储large指针
        if (large == NULL) {
            ngx_free(p);
            return NULL;
        }
    
        large->alloc = p;//在链表最后插入large
        large->next = pool->large;
        pool->large = large;
    
        return p;
    }
    

    最后内存的free就比较简单了,不过值得注意的是,小内存的话就不free的,只free large的。
    它变量pool->large的链表,逐一释放。如下,没有细节

    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;
    }

    最后是当程序退出时,destroy pool,也很简单,就是遍历large链表,free
    根据pool_.d.next 遍历pool,释放p就可以了。

      for (l = pool->large; l; l = l->next) {
            if (l->alloc) {
                ngx_free(l->alloc);
            }
        }
    
        for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
            ngx_free(p);
    
            if (n == NULL) {
                break;
            }
        }

    那么来说说这个ngx的内存管理的原则是,
    它分而治之,小块内存和大块内存采取不同的策略
    对于小块内存,不频繁清理,这样可以节省free和malloc的时间,且不容易造成内存碎片,但是程序耗费的内存可能会增大,
    大块内存可以及时清理,用链表维系,不易内存泄漏

    展开全文
  • 作者:deryzhou,腾讯 PCG 后台开发工程师Go 中怎么实现内存池,直接 map 可以吗?常用库里 GroupCache、BigCache 的内存池又是怎么实现的?有没有坑?对...
  • python怎么连接redis以前的问题 可以参考http://www.cnblogs.com/valleylord/p/3524918.html?utm_source=tuicoolpython怎么测试与redis的连接Redis端:192.168.100.132;port=6379Redis端:192.168.100.132客户端...
  • 目录 前言 内存池MemoryPool 存储内存池StorageMemoryPool...我们两篇文章的时间搞清楚了Spark存储中的“块”到底是怎么一回事,接下来我们就可以放心来看Spark Core存储子系统的细节了。前面已经提到过,Spark...
  • STL配置器(四)----内存池技术

    千次阅读 2016-04-08 22:48:22
    关于内存池,我相信大家都比较感兴趣,实现的版本也很多,但无论怎么实现,我觉得很重要的一点是:不能让管理内存池的成本太大!这是关键。比如,你管理100M的内存需要花50M的空间才能搞定,那我觉得不如直接...
  • 作者:deryzhou,腾讯 PCG 后台开发工程师Go 中怎么实现内存池,直接 map 可以吗?常用库里 GroupCache、BigCache 的内存池又是怎么实现的?有没有坑?对象池又是什么?想看重点的同学,可以直接看第 2 节 ...
  • 上一章那东西怎么用
  • Go 中怎么实现内存池,直接 map 可以吗?常用库里 GroupCache、BigCache 的内存池又是怎么实现的?有没有坑?对象池又是什么?想看重点的同学,可以直接看第 2 节 GroupCache 总结。0. 前言: tcmalloc 与 Go以前 ...
  • 大家生活中肯定都有这样的经验...作为程序员(C/C++)我们知道申请内存使用的是malloc,malloc其实就是一个通用的大众货,什么场景下都可以,但是什么场景下都可以就意味着什么场景下都不会有很高的性能。 malloc
  • 动态分区分配:产生很多外部碎片,虽然可以“紧凑”技术来处理,但“紧凑”技术时间代价很高。本质问题:连续分配方式要求进程占用的必须是一整段,连续的内存区域。(这个区域长度是不固定的)分页存储:如果允许...
  • 1、传输:什么样的通道传输数据给对方,BIO、NIO、AIO,IO模型在很大程度上决定了框架性能。 2、协议:采用什么样的通信协议,Http或内部私有协议。协议选择的不同,性能模型也不同。相比于公有协议,内部私有...
  • C#中的string是比特殊的类,说引用类型,但不存在堆里面,而且String str=new String(...然后我们ildasm.exe工具把它生成IL语言来看一看它里面是怎么玩的: .method private hidebysig static void Main(string[]
  • win10装了node.js执行gulp命令以后,内存会不断增长,分页缓冲也会增长,直至占满内存。 已经尝试把node.js回退回比较早期的版本,不好使。 只执行gulp命令,其他的服务都不用开启,也不需要浏览器访问,内存就...
  • 3.Tomcat 不支持EJB组件的开发,做j2ee项目时,最好还是weblogic服务,而且在做基本的sql语句时,最好连接,不要多用jdbc,odbc桥,因为在建立连接时最耗时间解决方法是让tomcat自己管理内存...
  • 有没有设置SQL Server最大使用的内存量?...另外这里限制的内存只是SQL Server缓冲的大小,SQL Server其它功能也是要占用内存的。还有64bit的是不需要开启AWE的。 EXEC sp_configure 'show advanced opti...
  • 文中将为您提供如何管理内存的细节,然后将进一步展示如何手工管理内存,如何使用引用计数或者内存池来半手工地管理内存,以及如何使用垃圾收集自动管理内存。 为什么必须管理内存 内存管理是计算机编程最为基本的...
  • 结论放前面 : list 就是个指针数组,指针数组里面对应存放了每个元素所在的地址 ...探究 python 是不是了一个整数缓冲缓存了指定范围的整数 python修改列表的值时的地址变化,一个蛮有意思的小实验 python 列表
  • 对象

    2014-03-16 21:09:25
    使用对象池加速游戏内存...相比内存池,对象池更易用更容易管理,而且还可以利用脏数据,也就是上次被回收掉的对象的数据。而且偶尔的空间分配失败其实不是那么重要(后面会讲怎么在会失败的情况下完成分配任务),游戏
  • 结构化语言里函数(子程序)调用最方便的实现方式就是栈,以至于现在绝大部分芯片都对栈提供芯片级的硬件支持,一条指令即可搞定栈的pop操作。栈的好处是:方便、快、有效避免内存碎片化。栈的问题是:不利于管理...
  • Unity 对象

    2020-07-13 21:28:04
    1、如果不使用对象怎么样?假设FPS游戏按下鼠标左键发射子弹,然后子弹到达相应的位置删除对象。如果突然场景中出现了1000个人每人发射30颗子弹,可能会造成卡死等,具体什么现象没验证过。最主要的是会触发.Net...
  • 1:连接的必知概念首先,我们还是老套的讲讲连接的基本概念,概念理解清楚了,我们也知道后面是怎么回事了。以前我们程序连接数据库的时候,每一次连接数据库都要一个连接,完后再释放。如果频繁的数据库操作...
  • 大神好:我ESD框架 开发了一个websocket服务,redis,mysql都是连接实来的,esd框架虽并不完善但也做了连接超时断开后,再次使用上连接时会重连,但发现一夜过后(也就是长达7,8个小时没有人使用)redis长连接重连...
  • 8.小数据,代码块

    2019-06-11 17:29:00
    15.小数据池 小数据池就是python 中一种提高效率的方式,固定数据...小数据池怎么用? a=1 b=1 #id 查看空间的内存地址 获取开辟空间的一种地址 print(id(a)) print(id(b)) 小数据池数字范围:-5~256 字符串: 1.字...
  • 蓄水抽样算法

    2020-12-03 17:38:41
    蓄水抽样问题 蓄水抽样算法是一种抽样算法,对于一个不知道大小的的集合(通常是流式数据),抽取的样本值能够保证随机。 ...那么蓄水抽样算法是怎么做的? 首先,我们要维护一个大小为k的数组

空空如也

空空如也

1 2 3 4 5 ... 9
收藏数 161
精华内容 64
关键字:

内存池怎么用