每日一篇--为嵌入式系统开发一套内存管理机制

2019-07-13 06:30发布

公司的项目都没有自己的内存管理机制,要使用内存时就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; }