该篇内容的代码例程来自正点原子,讲解分析来自于这位博主郭志凯。因为本身涉及到的知识不多,因此该篇内容99.99%都是从博主那里转过来的。
一、Malloc.h
1 |
|
二、Malloc.c
1 |
|
三、源码、思想讲解
1. 思想:将内存池分为块,首先定义每个块的字节数,和内存池的总字节数,用总字节数除以每个块的字节数得到块数
2. 内存池,实际上就是一个数组
3. 内存管理块,实际也是一个数组,总元素个数为内存块数,每个元素对应一个内存块,该元素非零时表示该内存块没有被占用
4. 将第一步中的信息用数组保存起来,方便后面的函数调用
5. 将内存抽象为一个结构体,传入的参数分别是,初始化函数,占用率函数,两个内存池(数组)的基地址,两个内存管理状态表(两个u16数组),两个内存池的就绪布尔值
6. 初始化函数,实际上就是将指定内存池(数组)内面的内容全部用0填充,将内存状态表(u16数组)全部用0填充,然后将该内存池的就绪布尔变量置1
7. 计算内存使用率(注意:得到的是块使用的比率,而不是字节使用的比率)
8. 复制,就是按字节依次赋值内容
9. 从起始位置将连续count个字节的区域用c填充
10. 分配内存(内部调用),成功:返回相对于数组首地址的偏移地址。
-> 判断指定的内存池是否已经初始化
-> 若传入参数为0,表示不需要分配,直接返回
-> 通过所需字节数对每个块的字节数分别取整,取余得到所需的连续块数
-> 从最后一个块往前面寻找所需的连续块,例如所需的块为3,当找到连续2块而,下一块已经被使用时,则将已经找的的连续块数清零,再在前面找连续的3块
-> 返回的偏移地址为所需连续块的起始块相对于内存池的偏移地址
-> 将即将用到的内存块对应的内存管理表中的元素置为所需的连续块数
11. 分配内存,首先判断偏移地址是否正确,然后返回连续块的首地址
12. 扩大分配内存,首先分配一个指定的内存,再将旧内存里面的内容拷贝到新内存(这里感觉战舰的源码有问题,旧的内存里面原来没有size个元素,却拷贝size个元素到新的空间),最后释放旧的内存空间,返回新的内存(块)首地址
13. 清除连续的内存块,成功:返回0
-> 首先通过偏移地址除以每个块的字节数,得到起始块的序号
-> 读取起始块对应的内存控制表元素,得到从起始块开始共要清除多少个连续的块
-> 所谓的清除,实际上只是将对应的内存控制表的元素清零,内存中的值未清零。
-> 为某个对象分配元素时,是分配的连续块,清除时,也是清除这几个连续块,不同对象占用不同的连续块,清除时,不会影响其他对象。
14. 内存释放函数,首先得出偏移地址,然后,调用上一步的函数释放内存