mysql層的內存分配

參考 http://www.cnblogs.com/justfortaste/p/3198406.htmlhtml

http://m.blog.csdn.net/blog/IT_PCode/17007833mysql

http://blog.chinaunix.net/uid-28364803-id-3419777.htmlsql

http://blog.chinaunix.net/uid-26896862-id-3412033.html數據庫

 

mysql數據庫分mysql層和存儲引擎層,每一個層都有各自的分配內存方法app

mysql層分配內存方法比較簡單less

當一個請求過來後,使用一個線程爲其服務,mysql層爲它分配內存ui

mysql層mem_rootthis

 

 

 

typedef struct st_used_mem
{                   /* struct for once_alloc (block) */
  struct st_used_mem *next;       /* Next block in use */
  unsigned int    left;           /* memory left in block  */
  unsigned int    size;           /* size of block */
} USED_MEM;

typedef struct st_mem_root
{
  USED_MEM *free;                  /* blocks with free memory in it */
  USED_MEM *used;                  /* blocks almost without free memory */
  USED_MEM *pre_alloc;             /* preallocated block */
  /* if block have less memory it will be put in 'used' list */
  size_t min_malloc;
  size_t block_size;               /* initial block size */
  unsigned int block_num;          /* allocated blocks counter */
  /* 
     first free block in queue test counter (if it exceed 
     MAX_BLOCK_USAGE_BEFORE_DROP block will be dropped in 'used' list)
  */
  unsigned int first_block_usage;

  void (*error_handler)(void);
} MEM_ROOT;

 

 

mysql內存池
mysql內部使用的內存管理程序,能夠實現屢次申請內存塊, 中途任什麼時候刻失敗, 或者下次使用前釋放內存, 無需再關心每次申請和釋放了哪些內存.
工做原理:
初始化定義每次分配的最小內存塊大小M,若是申請一次內存, 大小爲X, X大於M, 就分配一塊X的內存, 加入到管理鏈表中.若是小於的話, 看以前剩餘的還夠不夠, 若是足夠的話, 返回以前多餘的內存地址.若是不夠,則申請這麼大的內存, 也計入鏈表中。
釋放是一次性的,也能夠不釋放內存,而是標記已經使用的內存爲「未使用」,下次一樣的應用能夠繼續使用。
建立內存池
/*
 Initialize memory root

 SYNOPSIS
 init_alloc_root()
 mem_root       - memory root to initialize
 block_size     - size of chunks (blocks) used for memory allocation
 (It is external size of chunk i.e. it should include
 memory required for internal structures, thus it
 should be no less than ALLOC_ROOT_MIN_BLOCK_SIZE)
 pre_alloc_size - if non-0, then size of block that should be
 pre-allocated during memory root initialization.

 DESCRIPTION
 This function prepares memory root for further use, sets initial size of
 chunk for memory allocation and pre-allocates first block if specified.
 Altough error can happen during execution of this function if
 pre_alloc_size is non-0 it won't be reported. Instead it will be
 reported as error in first alloc_root() on this memory root.
 */

void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
        uint pre_alloc_size __attribute__((unused))) {
    DBUG_ENTER("init_alloc_root");
    mem_root->free = mem_root->used = mem_root->pre_alloc = 0;
    mem_root->min_malloc = 32;
    mem_root->block_size = block_size - ALLOC_ROOT_MIN_BLOCK_SIZE;
    mem_root->error_handler = 0;
    mem_root->block_num = 4; /* We shift this with >>2 */
    mem_root->first_block_usage = 0;

    if (pre_alloc_size) {
        if ((mem_root->free = mem_root->pre_alloc = (USED_MEM*) my_malloc(
                pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM)),
                MYF(0))))
                {
                    mem_root->free->size= pre_alloc_size+ALIGN_SIZE(sizeof(USED_MEM));
      mem_root->free->left= pre_alloc_size;
      mem_root->free->next= 0;
    }
    }

    DBUG_VOID_RETURN;
}
申請內存
gptr alloc_root(MEM_ROOT *mem_root, unsigned int Size) {
    uint get_size, block_size;
    gptr point;
    reg1 USED_MEM *next = 0;
    reg2 USED_MEM **prev;
    DBUG_ENTER("alloc_root");DBUG_ASSERT(alloc_root_inited(mem_root));

    Size = ALIGN_SIZE(Size);
    if ((*(prev = &mem_root->free)) != NULL)
    {
        if ((*prev)->left < Size
                && mem_root->first_block_usage++
                        >= ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP
                && (*prev)->left < ALLOC_MAX_BLOCK_TO_DROP)
                {
            next = *prev;
            *prev = next->next; /* Remove block from list */
            next->next = mem_root->used;
            mem_root->used = next;
            mem_root->first_block_usage = 0;
        }
        for (next = *prev; next && next->left < Size; next = next->next)
            prev = &next->next;
    }
    if (!next) { /* Time to alloc new block */
        block_size = mem_root->block_size * (mem_root->block_num >> 2);
        get_size = Size + ALIGN_SIZE(sizeof(USED_MEM));
        get_size = max(get_size, block_size);

        if (!(next = (USED_MEM*) my_malloc(get_size, MYF(MY_WME)))) {
            if (mem_root->error_handler)
                (*mem_root->error_handler)();
            return ((gptr) 0); /* purecov: inspected */
        }
        mem_root->block_num++;
        next->next = *prev;
        next->size = get_size;
        next->left = get_size - ALIGN_SIZE(sizeof(USED_MEM));
        *prev = next;
    }

    point = (gptr) ((char*) next + (next->size - next->left));
    /*TODO: next part may be unneded due to mem_root->first_block_usage counter*/
    if ((next->left -= Size) < mem_root->min_malloc) { /* Full block */
        *prev = next->next; /* Remove block from list */
        next->next = mem_root->used;
        mem_root->used = next;
        mem_root->first_block_usage = 0;
    }DBUG_RETURN(point);
}
釋放內存
/*
 Deallocate everything used by alloc_root or just move
 used blocks to free list if called with MY_USED_TO_FREE

 SYNOPSIS
 free_root()
 root        Memory root
 MyFlags        Flags for what should be freed:

 MY_MARK_BLOCKS_FREED    Don't free blocks, just mark them free
 MY_KEEP_PREALLOC    If this is not set, then free also the
 preallocated block

 NOTES
 One can call this function either with root block initialised with
 init_alloc_root() or with a bzero()-ed block.
 It's also safe to call this multiple times with the same mem_root.
 */

void free_root(MEM_ROOT *root, myf MyFlags) {
    reg1 USED_MEM *next, *old;
    DBUG_ENTER("free_root");

    if (!root) /* QQ: Should be deleted */
        DBUG_VOID_RETURN; /* purecov: inspected */
    if (MyFlags & MY_MARK_BLOCKS_FREE)
    {
        mark_blocks_free(root);
        DBUG_VOID_RETURN;
    }
    if (!(MyFlags & MY_KEEP_PREALLOC))
        root->pre_alloc = 0;

    for (next = root->used; next;) {
        old = next;
        next = next->next;
        if (old != root->pre_alloc)
            my_free((gptr) old, MYF(0));
    }
    for (next = root->free; next;) {
        old = next;
        next = next->next;
        if (old != root->pre_alloc)
            my_free((gptr) old, MYF(0));
    }
    root->used = root->free = 0;
    if (root->pre_alloc) {
        root->free = root->pre_alloc;
        root->free->left = root->pre_alloc->size - ALIGN_SIZE(sizeof(USED_MEM));
        TRASH_MEM(root->pre_alloc);
        root->free->next = 0;
    }
    root->block_num = 4;
    root->first_block_usage = 0;
    DBUG_VOID_RETURN;
}
內存池使用實例
void test_myalloc() {
    MEM_ROOT root;
    char *str;
    init_alloc_root(&root, 1 << 12, 1 << 10);
    str = (char *) alloc_root(&root, 1024 * sizeof(double));
    if (NULL == str)
        printf("cannot get memory for alloc root for str\n");
    strcpy(str, "hello\n");
    puts(str);
    //mark free, can be used again
    free_root(&root, MY_MARK_BLOCKS_FREE);
    //free, can not be used
    free_root(&root, 0);
}

 

 

void my_free(void *ptr)
{
  DBUG_ENTER("my_free");
  DBUG_PRINT("my",("ptr: %p", ptr));
  free(ptr);
  DBUG_VOID_RETURN;
}
相關文章
相關標籤/搜索