簡單的記憶體池實現gko_alloc

來源:互聯網
上載者:User

標籤:style   blog   http   color   io   os   ar   for   sp   

在用gpreftools最佳化gko_pool的時候我發現一個問題,malloc竟然成了效能瓶頸 由於在每個串連建立的時候gko_pool預設會為讀寫各分配2KB的buf備用,這個是比較固定的 每個串連的的生命週期會伴隨著4KB大小的記憶體malloc & free 正好可以寫個只能分配固定大小記憶體的“記憶體池”,基本思路就是每次分配一個大記憶體bucket(64MB),需要4KB的塊的時候就從bucket中取,當bucket沒有可用slot就再分配一個新的bucket,當bucket的所有slot都空閑就把bucket整體free。bucket中尋找槽位用的二分尋找實現,每個bit對應一個slot是否被佔用,廢話不說 上代碼: memory.h

/* * memory.h * *  Created on: Jun 8, 2012 *      Author: auxten */#ifndef GKO_MEMORY_H_#define GKO_MEMORY_H_#include <sys/types.h>#include <pthread.h>static const u_int32_t      SLOT_SIZE       =   4 * 1024;                   /// one page is goodstatic const u_int32_t      SLOT_COUNT      =   1 * 1024 * 1024;static const u_int32_t      M_MAP_SIZE      =   SLOT_COUNT / sizeof(u_int8_t);  /// bitmapstatic const u_int32_t      BUCKET_SIZE     =   64 * 1024 * 1024;static const int32_t        BUCKET_CAPACITY =   BUCKET_SIZE / SLOT_SIZE; /// capacity, 4096static const int32_t        BUCKET_COUNT    =   SLOT_COUNT / BUCKET_CAPACITY; /// 256static const int            INVILID_BLOCK   =   -1;class gkoAlloc{private:    pthread_mutex_t alloc_lock;    u_int8_t m_map[M_MAP_SIZE]; /// 1MB can fit L2 cache    void *  bucket_s[BUCKET_COUNT];    int16_t bucket_used[BUCKET_COUNT];    int latest_bucket;    int get_bit(u_int8_t * b);    int free_bit(u_int8_t * b, int index);public:    gkoAlloc(void);    int get_block(void);    int get_clear_block(void);    int get2x_block(int block_id);    void free_block(int block_id);    int clear_block(void *block, int c, size_t size);    void * id2addr(int block_id);};#endif /* GKO_MEMORY_H_ */ /* * memory.cpp * *  Created on: Jun 8, 2012 *      Author: auxten * *  only support little endian : x86 *///#define MEM_TEST#define _XOPEN_SOURCE 600#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <assert.h>#include <sys/types.h>#include "memory.h"gkoAlloc::gkoAlloc(void){    pthread_mutex_init(&alloc_lock, NULL);    memset((void *) m_map, 0, M_MAP_SIZE * sizeof(u_int8_t));    memset((void *) bucket_s, 0, BUCKET_COUNT * sizeof(void *));    memset((void *) bucket_used, 0, BUCKET_COUNT * sizeof(int16_t));    latest_bucket = 0;}void * gkoAlloc::id2addr(int block_id){    if (block_id < 0)        return NULL;    int bucket_no = block_id / BUCKET_CAPACITY;    int bucket_offset = SLOT_SIZE * (block_id % BUCKET_CAPACITY);    return ((char *)bucket_s[bucket_no]) + bucket_offset;}int gkoAlloc::get_bit(u_int8_t * b){    /**     *  idx     01234567     *  byte    11111010     *     *  return 5 and     *  byte    11111110     */    int i;    for (i = 0; i < 8; i++)    {        if ((u_int8_t)((*b >> 7 - i) << 7) == (u_int8_t)0u)            break;    }    *b |= (u_int8_t)( 1u << 7 - i);    return i;}int gkoAlloc::free_bit(u_int8_t * b, int index){    /**     *  idx     01234567     *  byte    11111110     *     *  return 5 and     *  byte    11111010     */    *b ^= (u_int8_t)( 1u << 7 - index);    return index;}int gkoAlloc::get_block(void){    int i;    int the_bucket;    int idx = INVILID_BLOCK;    u_int8_t * p_idx;    u_int64_t * bucket_start_idx;    u_int64_t * bucket_end_idx;    u_int64_t * bucket_idx;    pthread_mutex_lock(&alloc_lock);    for (i = 0; i < BUCKET_COUNT; i++)    {        the_bucket = (latest_bucket + i) % BUCKET_COUNT;        if (bucket_used[the_bucket] < BUCKET_CAPACITY)        {            latest_bucket = the_bucket;            break;        }    }    if (i == BUCKET_COUNT)    {        fprintf(stderr, "out of memory in pool\n");//        GKOLOG(FATAL, "out of memory in pool");        idx = INVILID_BLOCK;        goto GET_BLOCK_RET;    }    if (!bucket_s[the_bucket])    {        void * ptr;        if (!posix_memalign(&ptr, SLOT_SIZE, BUCKET_SIZE))        {            bucket_s[the_bucket] = ptr;            bucket_used[the_bucket] = 0;        }        else        {            fprintf(stderr, "posix_memalign fail\n");//            GKOLOG(FATAL, "posix_memalign fail");            idx = INVILID_BLOCK;            goto GET_BLOCK_RET;        }    }    bucket_start_idx = (u_int64_t *) &(this->m_map[the_bucket * BUCKET_CAPACITY / 8]);    bucket_end_idx = (u_int64_t *) &(this->m_map[(the_bucket + 1) * BUCKET_CAPACITY / 8]);    for (bucket_idx = bucket_start_idx;            bucket_idx < bucket_end_idx;            bucket_idx++)    {        if (*(u_int64_t *) bucket_idx != ~0uLL)        {            if (*(u_int32_t *) bucket_idx != ~0u)            {                if (*((u_int16_t *) bucket_idx) != (u_int16_t) ~0u)                {                    if (*(u_int8_t *) bucket_idx != (u_int8_t) ~0u)                    {                        p_idx = (u_int8_t *) bucket_idx + 0;                    }                    else                    {                        p_idx = (u_int8_t *) bucket_idx + 1;                    }                }                else                {                    if (*((u_int8_t *) bucket_idx + 2) != (u_int8_t) ~0u)                    {                        p_idx = (u_int8_t *) bucket_idx + 2;                    }                    else                    {                        p_idx = (u_int8_t *) bucket_idx + 3;                    }                }            }            else            {                if (*((u_int16_t *) bucket_idx + 2) != (u_int16_t) ~0u)                {                    if (*((u_int8_t *) bucket_idx + 4) != (u_int8_t) ~0u)                    {                        p_idx = (u_int8_t *) bucket_idx + 4;                    }                    else                    {                        p_idx = (u_int8_t *) bucket_idx + 5;                    }                }                else                {                    if (*((u_int8_t *) bucket_idx + 6) != (u_int8_t) ~0u)                    {                        p_idx = (u_int8_t *) bucket_idx + 6;                    }                    else                    {                        p_idx = (u_int8_t *) bucket_idx + 7;                    }                }            }            idx = get_bit(p_idx) +                    8 * (p_idx - (u_int8_t *) bucket_start_idx) +                    the_bucket * BUCKET_CAPACITY;            bucket_used[the_bucket] ++;            break;        }        else        {            continue;        }    }GET_BLOCK_RET:    pthread_mutex_unlock(&alloc_lock);    return idx;}void gkoAlloc::free_block(int block_id){    if (block_id < 0)        return;    int bucket_no = block_id / BUCKET_CAPACITY;    pthread_mutex_lock(&alloc_lock);    free_bit(&m_map[block_id / 8], block_id % 8);    if(--bucket_used[bucket_no] == 0)    {        free(bucket_s[bucket_no]);        bucket_s[bucket_no] = NULL;    }    else    {        latest_bucket = bucket_no;    }    pthread_mutex_unlock(&alloc_lock);}#ifdef MEM_TESTint main(){    gkoAlloc mem;    for (int i = 0; i < BUCKET_CAPACITY - 1; i++)    {        int k = mem.get_block();        printf("%d, %d\n", i, k);        if (i != k)        {            break;        }    }    int blk1 = mem.get_block();    int blk2 = mem.get_block();    int blk3 = mem.get_block();    printf("%p\n", mem.id2addr(blk1));    printf("%p\n", mem.id2addr(blk2));    printf("%p\n", mem.id2addr(blk3));    mem.free_block(blk1);    mem.free_block(blk2);    mem.free_block(blk3);    return 0;}#endif

 

編譯測試:

g++ -DMEM_TEST memory.cpp -o memory && ./memory

  github:https://github.com/auxten/gkoAlloc

   

簡單的記憶體池實現gko_alloc

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.