找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3377|回复: 2

【C】简单的malloc和free的实现

[复制链接]
发表于 2020-10-26 14:41:39 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
这里简单实现了cstdlib的动态内存管理函数malloc、calloc、realloc和free
大致原理是先申请一个数组作为内存空间,然后使用链表连接每个申请的内存块。如果要释放内存,就从链表中移除相应的内存块。
在没有动态内存管理的环境中,以下代码能派上用场替代malloc函数等。
使用前需要先调用mpkInitMemory函数。
这是头文件:

  1. #ifndef _MEMPKG_H_
  2. #define _MEMPKG_H_

  3. #include <stddef.h> /* Using type size_t. */

  4. typedef unsigned char UCHART, * PUCHAR;

  5. typedef struct st_BLOCK_HEADER
  6. {
  7.         struct st_BLOCK_HEADER * pnext;
  8.         PUCHAR pblock;
  9.         size_t size;
  10. } BLOCK_HEADER, * P_BLOCK_HEADER;

  11. #define MEM_SIZ (8192) /* Alter this macro to control the size of a heap. */

  12. void   mpkInitMemory(void);
  13. void * memcpy       (void *       dst, void *       src, size_t size);
  14. void * memset       (void *       s,   int          c,   size_t n);
  15. void * malloc       (size_t       size);
  16. void   free         (void *       ptr);
  17. void * realloc      (void *       ptr, size_t       size);
  18. void * calloc       (size_t       n,   size_t       size);
  19. int    memcmp       (const void * s1,  const void * s2,  size_t n);

  20. #define memmove(dst, src, size) memcpy(dst, src, size)

  21. #endif
复制代码

源文件:

  1. #include "mempkg.h"

  2. UCHART volatile array[MEM_SIZ]; /* Create a linear address space. */

  3. const PUCHAR volatile pmem = array;

  4. volatile P_BLOCK_HEADER phead = NULL; /* This is the header pointer of block chain. */

  5. /* Invoke this function before you use any function of this package.
  6. */
  7. void mpkInitMemory(void)
  8. {
  9.         phead = (P_BLOCK_HEADER)pmem;
  10.         phead->pblock = pmem + sizeof(BLOCK_HEADER);
  11.         phead->pnext = (P_BLOCK_HEADER)(pmem + MEM_SIZ - sizeof(BLOCK_HEADER));
  12.         phead->size = 0;
  13.         phead->pnext->pblock = pmem + MEM_SIZ;
  14.         phead->pnext->pnext = NULL;
  15.         phead->pnext->size = 0;
  16. }

  17. void * memcpy(void * dst, void * src, size_t size)
  18. {
  19.         char * sc1;
  20.         const char * sc2;
  21.         sc1 = dst;
  22.         sc2 = src;
  23.         if (sc2 < sc1 && sc1 < sc2 + size)
  24.                 for (sc1 += size, sc2 += size; 0 < size; --size)
  25.                         *--sc1 = *--sc2;
  26.         else
  27.                 for (; 0 < size; --size)
  28.                         *sc1++ = *sc2++;
  29.         return dst;
  30. }

  31. void * memset(void * s, int c, size_t n)
  32. {
  33.         const UCHART uc = c;
  34.         unsigned char * su;
  35.         for (su = s; 0 < n; ++su, --n)
  36.                 *su = uc;
  37.         return s;
  38. }

  39. void * malloc(size_t size)
  40. {
  41.         if (size > 0)
  42.         {
  43.                 P_BLOCK_HEADER pnode, pnew;
  44.                 for (pnode = phead; NULL != pnode; pnode = pnode->pnext)
  45.                 {
  46.                         if (pnode->pnext != NULL)
  47.                         {        /* Test available space for the new block. */
  48.                                 if (pnode->pnext->pblock - sizeof(BLOCK_HEADER) - pnode->pblock - pnode->size >=
  49.                                         size + sizeof(BLOCK_HEADER))
  50.                                 {
  51.                                         pnew = (P_BLOCK_HEADER)(pnode->pblock + pnode->size);
  52.                                         /* Initialize the new block header and assign new block. */
  53.                                         pnew->pblock = pnode->pblock + pnode->size + sizeof(BLOCK_HEADER);
  54.                                         pnew->size = size;
  55.                                         pnew->pnext = pnode->pnext;
  56.                                         pnode->pnext = pnew;
  57.                                         return pnew->pblock;
  58.                                 }
  59.                         }
  60.                         else
  61.                                 break;
  62.                 }
  63.         }
  64.         return NULL;
  65. }

  66. void free(void * ptr)
  67. {        /* Preserve the tail and header block structure. */
  68.         if (pmem == ptr || pmem + MEM_SIZ == ptr)
  69.                 return;
  70.         if (NULL != ptr)
  71.         {
  72.                 P_BLOCK_HEADER pnode;
  73.                 for (pnode = phead; NULL != pnode; pnode = pnode->pnext)
  74.                 {
  75.                         if (NULL != pnode->pnext && ptr == pnode->pnext->pblock)
  76.                         {
  77.                                 pnode->pnext = pnode->pnext->pnext;
  78.                                 return;
  79.                         }
  80.                 }
  81.         }
  82.         return;
  83. }

  84. void * realloc(void * ptr, size_t size)
  85. {        /* Preserve the tail and header block structure. */
  86.         if (pmem == ptr || pmem + MEM_SIZ == ptr)
  87.                 return NULL;
  88.         if (NULL == ptr && size > 0)
  89.                 return malloc(size);
  90.         else if (size > 0)
  91.         {
  92.                 P_BLOCK_HEADER pnode;
  93.                 for (pnode = phead; NULL != pnode; pnode = pnode->pnext)
  94.                 {
  95.                         if (NULL != pnode->pnext && ptr == pnode->pnext->pblock)
  96.                         {
  97.                                 if (size == pnode->pnext->size)
  98.                                         return ptr;
  99.                                 else if (pnode->pnext->pnext->pblock - sizeof(BLOCK_HEADER) - pnode->pblock - pnode->size >=
  100.                                         size + sizeof(BLOCK_HEADER))
  101.                                 {
  102.                                         pnode->pnext->size = size;
  103.                                         return ptr;
  104.                                 }
  105.                                 else
  106.                                 {
  107.                                         void * newptr = malloc(size);
  108.                                         if (NULL != newptr)
  109.                                         {
  110.                                                 memcpy(newptr, ptr, pnode->pnext->size);
  111.                                                 free(ptr);
  112.                                         }
  113.                                         return newptr;
  114.                                 }
  115.                         }
  116.                 }
  117.         }
  118.         return NULL;
  119. }

  120. void * calloc(size_t n, size_t size)
  121. {
  122.         void * rtn = malloc(size * n);
  123.         memset(rtn, 0, size * n);
  124.         return rtn;
  125. }

  126. int memcmp(const void * s1, const void * s2, size_t n)
  127. {
  128.         PUCHAR su1, su2;
  129.         for (su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n)
  130.                 if (*su1 != *su2)
  131.                         return *su1 < *su2 ? -1 : 1;
  132.         return 0;
  133. }
复制代码

本帖被以下淘专辑推荐:

回复

使用道具 举报

发表于 2020-10-27 00:27:37 | 显示全部楼层
一种裸机上管理内存的感觉,让我想到了在DOS年代,捅穿A20地址线,然后写16 MB内存的一些DOS游戏。

但,像STM32这样的单片机上,然后像STM32CubeIDE这样的开发环境提供的malloc其实是静态分配地址,就像一个宏,它给你局部起了一个static char mem[size];然后这块内存妥妥地进入了链接器脚本的.bss段。对应的,单片机上的free是没有任何行为的。

另外,现在的桌面机或者服务器环境,我为了实现高频的内存分配释放的效果,写过内存池,然后感觉一个比较大的难点是如何实现多线程环境下,能尽可能不锁住线程,实现高效的内存分配释放。
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-10-27 14:01:26 | 显示全部楼层
这段代码还有个缺点就是容易形成内存碎片,本来想实现一个伙伴系统的无奈功夫不到家没有实现成功。
在多线程环境下这段代码必须加锁,不然内存会被写乱。
另外,楼上可以参考一下glibc的malloc来获得灵感。
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-21 17:42 , Processed in 0.032791 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表