zoukankan      html  css  js  c++  java
  • SGI 第二级配置器__default_alloc_template核心内存分配函数chunk_alloc解析

      其实题目有些哗众取宠,主要想表达的是对chunk_alloc函数中两个地方存在疑问,想问问诸位怎么理解这两处的。

    下面先给出chunk_alloc代码实现,同时大概说明一下函数的功能以及每一处代码的作用。

    SGI的内存配置器分成两层:第一层直接调用malloc,第二层是自己做了一个内存池来分配。下面说下第二层配置器的思路:

    第二层配置器首先设置了一个free_list[16]的数组,数组中是指针,分别指向一块内存,指针类型定义如下:

    union obj {

      union obj *free_list_link;

      char client_data[1];

    };

    总之,free_list每个下标链接的内存大小为:8B、16B、24B、32B、40B、...、128B。共16个。

    现在假如要分配一块32B的内存,但free_list[3]所指向的指针为NULL,即空闲链表free_list中没有32B的内存,这时候就需要通过下面的_S_chunk_alloc来分配内存给free_list了。默认每次分配是分配20个大小为32B的内存。

    即_S_chunk_alloc第二个参数传入值为20,但系统不一定能分配20个,所以用的是引用。_S_chunk_malloc主要分三种情况来处理:

    1、现有内存池容量满足你的需求:32B * 20个,直接返回给你这么大一块内存;

    2、现有内存池容量不能满足这么多个,即20个,但可以满足1个,那先给你free_list对应项分配一个32B再说;

    3、现有内存池容量连一个都满足不了,那只能利用malloc从堆中分配内存。

      从堆中分配内存时,首先把当前内存池中剩余的一些零碎内存赋给free_list中;

      然后从堆中malloc内存,修改内存池的_S_start_free、_S_end_free指针。(这两个指针分别指向内存池的起始地址和结束地址)。

      再然后递归调用_S_chunk_malloc函数。

    我的问题是:1、重置零碎内存时是否有问题,如下代码中所示。

          2、malloc新的内存之后,修改_S_end_free的代码是否正确。

    全部代码如下,我的疑问解释说明再下面,大家先看下代码理解一下这个函数,然后看下我的思路哪里出错了,谢谢!

    template <bool __threads, int __inst>
    char*
    __default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, 
                                                                int& __nobjs)
    {
        char* __result;
        size_t __total_bytes = __size * __nobjs;
        size_t __bytes_left = _S_end_free - _S_start_free; // 内存池剩余空间
    
        if (__bytes_left >= __total_bytes) { // 内存池剩余空间完全满足需求
            __result = _S_start_free;
            _S_start_free += __total_bytes;
            return(__result);
        } else if (__bytes_left >= __size) { // 内存池剩余空间不能完全满足需求,但足够供应一个(含)以上的区块
            __nobjs = (int)(__bytes_left/__size);
            __total_bytes = __size * __nobjs;
            __result = _S_start_free;
            _S_start_free += __total_bytes;
            return(__result);
        } else { // 内存池剩余空间连一个区块的大小都无法提供
            size_t __bytes_to_get = 
    	  2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
            // Try to make use of the left-over piece.
    		// 把内存池当前剩下的一些小残余零头利用一下。
            if (__bytes_left > 0) {
                _Obj* __STL_VOLATILE* __my_free_list =
                            _S_free_list + _S_freelist_index(__bytes_left); // 这里对吗?假如__bytes_left = 15,则_S_freelist_index(15) = 1,
    																		// 即16B的位置,而实际上只剩下了15B?
    
                ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
                *__my_free_list = (_Obj*)_S_start_free;
            }
            _S_start_free = (char*)malloc(__bytes_to_get);
            if (0 == _S_start_free) {
                size_t __i;
                _Obj* __STL_VOLATILE* __my_free_list;
    	    _Obj* __p;
                // Try to make do with what we have.  That can't
                // hurt.  We do not try smaller requests, since that tends
                // to result in disaster on multi-process machines.
                for (__i = __size;
                     __i <= (size_t) _MAX_BYTES;
                     __i += (size_t) _ALIGN) {
                    __my_free_list = _S_free_list + _S_freelist_index(__i);
                    __p = *__my_free_list;
                    if (0 != __p) {
                        *__my_free_list = __p -> _M_free_list_link;
                        _S_start_free = (char*)__p;
                        _S_end_free = _S_start_free + __i; // 这里确定每一块内存大小都是__i吗?
                        return(_S_chunk_alloc(__size, __nobjs));
                        // Any leftover piece will eventually make it to the
                        // right free list.
                    }
                }
    	    _S_end_free = 0;	// In case of exception.
                _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
                // This should either throw an
                // exception or remedy the situation.  Thus we assume it
                // succeeded.
            }
            _S_heap_size += __bytes_to_get;
            _S_end_free = _S_start_free + __bytes_to_get;
            return(_S_chunk_alloc(__size, __nobjs));
        }
    }
    

      我的问题解释:

    1、假如__bytes_left = 15B,那么_S_freelist_index(__bytes_left) = 1,即是说应该把15B放到free_list中16B的这一项里面,这不错了吗?

    2、_S_end_free = _S_start_free + __i;怎么就可以确定free_list中对应__i这一项的大小都是__i,难道不会出现容量>__i,但小于__i + 8的吗?这样_S_end_free不就出错了吗?

  • 相关阅读:
    博客园cnblogs for win8 托管到GitHub开源
    html5 canvas 画图表
    回文数
    SpringBoot+logback实现按业务输出日志到不同的文件
    Class.forName() 与 ClassLoader.loadClass()的区别
    Easypoi实现单模板生成多页word文档
    普通Java项目中使用Sl4j+Log4j2打印日志
    SpringBoot集成JWT
    Java8_Lambda表达式
    SpringBoot自定义Condition注解
  • 原文地址:https://www.cnblogs.com/ziyoudefeng/p/3346513.html
Copyright © 2011-2022 走看看