系统层的思索(1) --- 为嵌入式系统开发一套内存管理机制

公司的项目都没有自己的内存管理机制,要使用内存时就malloc,不用时就free,感觉有效率问题,而且有内存泄漏的隐患,因此我决定设计一套给嵌入式linux设备使用的内存管理机制(很大部分参考了某开源web服务器中的设计)。

设计思想综述

用Alloc结构体表示一个内存块,内存块的大小有13个等级,每个等级分别是:

16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536字节。

 #define MAX_CLASS 13
typedef struct Alloc {
    union {
        void    *next;                          /**< Pointer to next in q */
        int     size;                             /**< Actual requested size */
    } u;
    int         flags;                          /**< Per block allocation flags */

} Alloc;

上面的结构体中有个指针next,用于将所有相同大小的内存块串成链表。

13种大小的内存块,就意味着有13条链表,链表首元素存放在全局数组中:

static Alloc    *qhead[MAX_CLASS];             /* Per class block q head */

对于大小在64k以内的内存需求,均到我们预先分配的内存块去取,除非内存块没有空闲了。

64k以上的内存需求,直接用malloc分配。


实际实现:

 #define MAX_CLASS 13
typedef struct Alloc {
    union {
        void    *next;                          /**< Pointer to next in q */
        int     size;                             /**< Actual requested size */
    } u;
    int         flags;                          /**< Per block allocation flags */

} Alloc;



//对齐函数,如果size能被4整除,返回size,否则返回下一个比size大的能被4整除的数,在内存分配时用到

#define ROUNDUP4(size) ((size) % 4) ? (size) + (4 - ((size) % 4)) : (size)

#define USE_MALLOC        0x1             /**< Okay to use malloc if required */
#define USER_BUF          0x2             /* User supplied buffer for mem */
#define INTEGRITY         0x8124000       /* Integrity value */

#define INTEGRITY_MASK    0xFFFF000       /* Integrity mask */

#define DEFAULT_MEM   (64 * 1024)         /**< Default memory allocation */
#define SHIFT         4                   /**< Convert size to class */
#define ROUND         ((1 << (B_SHIFT)) - 1)
#define MALLOCED      0x80000000          /* Block was malloced */
#define FILL_CHAR     (0x77)              /* Fill byte for buffers */
#define FILL_WORD     (0x77777777)        /* Fill word for buffers */

static Alloc    *qhead[MAX_CLASS];             /* Per class block q head */
static char         *freeBuf;                           /* Pointer to free memory */
static char         *freeNext;                          /* Pointer to next free mem */
static int          freeSize;                           /* Size of free memory */
static int          freeLeft;                           /* Size of free left for use */
static int          controlFlags = WEBS_USE_MALLOC;     /* Default to auto-malloc */

static int          openCount = 0;                     /* 使用该片内存的进程数 */

typedef void (*MemNotifier)(ssize size);

static MemNotifier memNotifier;//留给用户的内存分配通知函数,见下面

该函数必须在程序启动后就调用,参数buf不为NULL,则表示使用用户提供的buf作为系统内存,buf为null则会用malloc来分配系统内存。

int openAlloc(void *buf, int bufsize, int flags)
{

    controlFlags = flags;
    /*
        If openAlloc already called by a shared process, just increment the count and return
     */
    if (++openCount > 1) {
        return 0;
    }
    if (buf == NULL) {
        if (bufsize == 0) {
            bufsize = DEFAULT_MEM;//没有指定内存大小时,默认分配64k最为系统的内存
        }
        bufsize = ROUNDUP4(bufsize);
        if ((buf = malloc(bufsize)) == NULL) {
            /*
                Resetting wopenCount so client code can decide to call wopenAlloc() again with a smaller memory request.
            */
             --openCount;
            return -1;
        }
    } else {
        controlFlags |= USER_BUF;
    }
    freeSize = freeLeft = bufsize;
    freeBuf = freeNext = buf;
    memset(qhead, 0, sizeof(qhead));
    return 0;

该函数必须在程序退出之前调用

 void closeAlloc()
{
    if (--openCount <= 0 && !(controlFlags & USER_BUF)) {
        free(freeBuf);
        openCount = 0;
    }

}

接下来就是重要的内存分配函数了。

该函数是用于计算你需要的内存字节数size对应我们前面定义的13个等级中的哪一个等级

static int allocGetSize(int size, int *q)

{
    int mask;


    mask = (size == 0) ? 0 : (size-1) >> SHIFT;
    for (*q = 0; mask; mask >>= 1) {
        *q = *q + 1;
    }
    return ((1 << (SHIFT + *q)) + sizeof(Alloc));

}


void *alloc(int size)

{
    Alloc   *bp;
    int         q, memSize;


    /*
        Call openAlloc with default values if the application has not yet done so
     */
    if (freeBuf == NULL) {
        if (openAlloc(NULL, DEFAULT_MEM, 0) < 0) {
            return NULL;
        }
    }
    if (size < 0) {
        return NULL;
    }
    memSize = allocGetSize(size, &q);//计算该大小对应哪个等级


  //超过了我们定义的等级,也就是说size>=65535

    if (q >= MAX_CLASS) {
        /*
            Size if bigger than the maximum class. Malloc if use has been okayed
         */
        if (controlFlags & USE_MALLOC) {
            memSize = ROUNDUP4(memSize);
            bp = (Alloc*) malloc(memSize);
            if (bp == NULL) {
                if (memNotifier) {
                    (memNotifier)(memSize);
                }
                return NULL;
            }
        } else {
            if (memNotifier) {
                (memNotifier)(memSize);
            }
            return NULL;
        }
        /*
            the u.size is the actual size allocated for data
         */
        bp->u.size = memSize - sizeof(Alloc);
        bp->flags = MALLOCED;


    } else if ((bp = qhead[q]) != NULL) {//取出链表的第一个空闲内存块
        /*
            Take first block off the relevant q if non-empty
         */
        qhead[q] = bp->u.next;//更新头结点
        bp->u.size = memSize - sizeof(Alloc);
        bp->flags = 0;


    } else {
        if (freeLeft > memSize) {
            /*
                The q was empty, and the free list has spare memory so create a new block out of the primary free block
             */
            bp = (Alloc*) freeNext;
            freeNext += memSize;
            freeLeft -= memSize;
            bp->u.size = memSize - sizeof(Alloc);
            bp->flags = 0;


        } else if (controlFlags & USE_MALLOC) {
            /*
                Nothing left on the primary free list, so malloc a new block
             */
            memSize = ROUNDUP4(memSize);
            if ((bp = (Alloc*) malloc(memSize)) == NULL) {
                if (memNotifier) {
                    (memNotifier)(memSize);
                }
                return NULL;
            }
            bp->u.size = memSize - sizeof(Alloc);
            bp->flags = MALLOCED;


        } else {
            if (memNotifier) {
                (memNotifier)(memSize);
            }
            return NULL;
        }
    }
    bp->flags |= INTEGRITY;
    return (void*) ((char*) bp + sizeof(Alloc));

}


重新为一个内存块分配空间

void *wrealloc(void *mp, int newsize)
{
    Alloc   *bp;
    void    *newbuf;


    if (mp == NULL) {
        return walloc(newsize);
    }
    bp = (Alloc*) ((char*) mp - sizeof(Alloc));
    assert((bp->flags & INTEGRITY_MASK) == INTEGRITY);


    /*
        If the allocated memory already has enough room just return the previously allocated address.
     */
    if (bp->u.size >= newsize) {
        return mp;
    }
    if ((newbuf = walloc(newsize)) != NULL) {
        memcpy(newbuf, mp, bp->u.size);
        wfree(mp);
    }
    return newbuf;
}


猜你喜欢

转载自blog.csdn.net/handsomehong/article/details/80422508