内存管理 malloc free 的实现

时间:2021-11-25 03:16:02

libc 中提供非常好用的  malloc free 功能,如果自己实现一个,应该怎么做。

要实现 malloc free 需要有 可以分配内存使用的堆,和记录内存使用情况的链表。

如下图所示,堆从高向低分配,链表从低向高分配,图是 ps 画的。

内存管理 malloc free 的实现

 1 /* 管理堆的链表 */
2 typedef struct A_BLOCK_LINK
3 {
4 char *pV; /* 内存实际物理地址 */
5 int index; /* 内存编号 */
6 char empty; /* 1 空 0 非空 */
7 int heapLen; /* 分配长度 */
8 struct A_BLOCK_LINK *pxNextFreeBlock; /* 上个节点 */
9 struct A_BLOCK_LINK *pxPrevFreeBlock; /* 下个节点 */
10 } BlockLink_t;

 

这里的对应关系是,链表 1 对应 最后一个堆,链表 2对应 最后2个堆。

如何初始化?

1,先计算出来,共能分配多少块内存

2,分配管理链表

如何找到合适的可以分配的内存?

这里从链表1 开始向后查找,当未使用的内存长度满足要求时,将最后找到的链表的,堆地址返回给 申请者。

如何free 内存?

因为 free 只传过来一个 ,最初申请的内存地址,没有传入长度,这里也需要在 链表结构体中进行记录

详细的代码,可以去置顶的 github 项目。 

经过测试在, ubuntu16.4 gcc 5.4 中运行正常,free 后的内存,可以被重新 malloc 。

目前还没有实现,内存碎片整理功能。仅有一个空实现。 后期在更新。

实现代码:

  1 #include <string.h>
2 #include <stdio.h>
3 #include "sram.h"
4
5 //以下定义大小是为了直观的看到程序运行分配结果,取10进制数
6 //整个SRAM大小
7 #define SRAM_SIZE (1000)
8
9 //堆分块大小
10 #define HeapBlockSIZE (100)
11
12 //以下代码在 GCC 中演示使用编译器分一个大的SRAM 在实际硬件中,直接写内存开始地址就可以
13 //#define SRAM_BASE_ADDR 0
14 static char SRAM_BASE_ADDR[SRAM_SIZE] = {0};
15
16 /* 管理堆的链表 */
17 typedef struct A_BLOCK_LINK
18 {
19 char *pV; /* 内存实际物理地址 */
20 int index; /* 内存编号 */
21 char empty; /* 1 空 0 非空 */
22 int heapLen; /* 分配长度 */
23 struct A_BLOCK_LINK *pxNextFreeBlock; /* 上个节点 */
24 struct A_BLOCK_LINK *pxPrevFreeBlock; /* 下个节点 */
25 } BlockLink_t;
26
27 //头节点
28 static char *HeapHead = NULL;
29 //块数量
30 static int BlockTotal = 0;
31
32 void TraceHeap(void)
33 {
34 BlockLink_t *pTempBlockLink = (BlockLink_t *)HeapHead;
35 printf("\r\n##########TraceHeap#############\r\n");
36 while(pTempBlockLink)
37 {
38 printf("index: %d empty:%d addr:%d \r\n", pTempBlockLink->index, pTempBlockLink->empty, pTempBlockLink->pV - SRAM_BASE_ADDR);
39 pTempBlockLink = pTempBlockLink->pxNextFreeBlock;
40 }
41 printf("\r\n##########TraceHeap#############\r\n");
42 }
43
44 //堆 Heap 分配初始化
45 void InitHeap(void)
46 {
47 BlockLink_t *pBlockLink, *pTempBlockLink = NULL;
48 int i = 0;
49 char *pHeapStart = (char *)SRAM_BASE_ADDR;
50 char *pHeapEnd = (char *)(SRAM_BASE_ADDR + SRAM_SIZE);
51 pHeapEnd -= HeapBlockSIZE;
52 BlockTotal = SRAM_SIZE / (HeapBlockSIZE + sizeof(BlockLink_t));
53 while(i < BlockTotal)
54 {
55 pBlockLink = (BlockLink_t *)pHeapStart;
56 pBlockLink->pxPrevFreeBlock = pTempBlockLink;
57 pBlockLink->pV = pHeapEnd;
58 pBlockLink->index = i;
59 pBlockLink->empty = 1;
60 pBlockLink->heapLen = 0;
61 //指针重定位
62 pHeapEnd -= HeapBlockSIZE;
63 pHeapStart += sizeof(BlockLink_t);
64 //双向链表的上一个
65 pTempBlockLink = pBlockLink;
66 pBlockLink->pxNextFreeBlock = (BlockLink_t *)pHeapStart;
67 i++;
68 }
69 pBlockLink->pxNextFreeBlock = NULL;
70 HeapHead = (char *)SRAM_BASE_ADDR;
71 }
72
73 static BlockLink_t *FindHeap(char *addr)
74 {
75 BlockLink_t *pTempBlockLink = (BlockLink_t *)HeapHead;
76 //从低向高查找可用的内存
77 while(pTempBlockLink)
78 {
79 if(pTempBlockLink->pV == addr)
80 {
81 return pTempBlockLink;
82 }
83 //切换下一节点
84 pTempBlockLink = pTempBlockLink->pxNextFreeBlock;
85 }
86 return NULL;
87 }
88
89 //查找可用的连续内存
90 static void *SramFindHeap(int size)
91 {
92 char *mem;
93 int seriesSize = 0; //已查找到连续用的内存
94 BlockLink_t *pTempBlockLink; //头节点
95 pTempBlockLink = (BlockLink_t *)HeapHead;
96 //从低向高查找可用的内存
97 while(pTempBlockLink)
98 {
99 //如果是未使用的内存
100 if(pTempBlockLink->empty)
101 {
102 seriesSize += HeapBlockSIZE;
103 }
104 else
105 {
106 seriesSize = 0;
107 }
108 //如果查找到连续未使用的内存
109 if(seriesSize >= size)
110 {
111 //返回内存堆开始地址
112 pTempBlockLink->heapLen = seriesSize; //设置分配堆长度
113 mem = pTempBlockLink->pV;
114
115 //将内存标记为 已使用
116 while(seriesSize && pTempBlockLink)
117 {
118 seriesSize -= HeapBlockSIZE;
119 pTempBlockLink->empty = 0;
120 pTempBlockLink = pTempBlockLink->pxPrevFreeBlock;
121 }
122 return mem;
123 }
124 //切换下一节点
125 pTempBlockLink = pTempBlockLink->pxNextFreeBlock;
126 }
127 return NULL;
128 }
129
130 //内存碎片整理
131 static void SramMerge(void)
132 {
133
134 }
135
136 void *SramMalloc(size_t xWantedSize)
137 {
138 char *mem;
139
140 if(! HeapHead)
141 {
142 InitHeap();
143 }
144 //地址对齐
145
146 mem = SramFindHeap(xWantedSize);
147 if(mem)
148 {
149 return mem;
150 }
151 //如果没有查找到 整理内存碎片
152 SramMerge();
153
154 //仍然分配不成功 返回错误
155 mem = SramFindHeap(xWantedSize);
156 if(mem)
157 {
158 return mem;
159 }
160 return NULL;
161 }
162
163 void SramFree( void *pv )
164 {
165 int heapLen = 0;
166 //释放内存 从堆的高位开始向低位查找
167 BlockLink_t *pTempHeap = FindHeap(pv);
168 heapLen = pTempHeap->heapLen;
169 while(heapLen && pTempHeap)
170 {
171 //设为空闲状态
172 pTempHeap->empty = 1;
173 pTempHeap->heapLen = 0;
174 //查找上个节点
175 pTempHeap = pTempHeap->pxPrevFreeBlock;
176 heapLen -= HeapBlockSIZE;
177 }
178 }