程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> SGI 第二級配置器__default_alloc_template核心內存分配函數chunk_alloc解析

SGI 第二級配置器__default_alloc_template核心內存分配函數chunk_alloc解析

編輯:C++入門知識

  其實題目有些嘩眾取寵,主要想表達的是對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不就出錯了嗎?

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved