【内存管理】Vxworks内存管理

嵌入式管理,第一个小作业。实现自己的内存管理程序。

题目:统计程序使用内存块大小的频率,实现内存管理程序。目的为减少外部碎片,(宁可换取内部碎片)功能包括

①初始化内存区域

②申请内存,返回内存首地址

③释放内存

④展示内存占用情况

情景假设:如程序经常使用30-50字节的小块内存区域,较长使用500-1000的大块内存区域,以及较少的1000+的内存区域。

实现思路:

1.设计模型

(1)对于小内存块(SMALLSIZE字节)和大内存块(BIGSIZE字节)的管理如下图。

该部分共有四个数据结构 ↓

1/*小内存块结构*/ 2typedef struct{ 3 char data[SMALLSIZE];/*存放data域*/ 4}small_block; 5 6/*大内存块结构 */ 7typedef struct{ 8 char data[BIGSIZE];/*存放data域*/ 9}big_block; 10 11/*小内存块管理结构*/ 12typedef struct{ 13 small_block * base_add;/*小内存块的基地址*/ 14 int busy_num;/*被使用的数量 */ 15 char busy[SMALLNUM];/*每个小内存块的使用情况*/ 16}small_block_manage; 17 18/*大内存块管理结构*/ 19typedef struct{ 20 big_block * base_add;/*大内存块的基地址*/ 21 int busy_num;/*被使用的数量 */ 22 char busy[BIGNUM]; /*每个大内存块的使用情况*/ 23}big_block_manage; 24
1#define SMALLSIZE 50 /*小内存块数据域的大小 */ 2#define SMALLNUM 20 /*小内存块的个数 */ 3#define BIGSIZE 1000 /*大内存块数据域的大小 */ 4#define BIGNUM 4 /*大内存块的个数 */ 5

①小内存块为SMALLSIZE(50)字节,用于用户对小内存的使用。共SMALLNUM(20)个连续的小内存块。

②大内存块为BIGSIZE(1000)字节,用户用户对大内存的使用。共BIGNUMM(4)个连续的大内存块。

③小内存块管理结构,base_add记录连续的小内存块中 首块 小内存块的地址,busy_num记录小内存块被使用的数量,busy[SMALLNUM]记录小内存块具体使用情况。available可用,busy已占用。

④大内存块管理结构,与③类似。

1#define BLOCKAVAILABLE 0 2#define BLOCKBUSY 1 3

计算好小内存块和大内存块占用的总字节数,调用原有的malloc函数,申请一大块连续的包含管理区域与内存区域的地址。(申请pre_alloc_size字节。)

1/*计算首先要申请多少字节的内存地址*/ 2 small_size = SMALLNUM*sizeof(small_block); 3 big_size = BIGNUM*sizeof(big_block); 4 manage_size = sizeof(small_block_manage) + sizeof(big_block_manage); 5 pre_alloc_size = small_size + big_size + manage_size; 6 7 printf(" ========================================================\n"); 8 printf("||\t小内存块数量:%d,每块占用%d字节,共%d字节\t||\n",SMALLNUM,sizeof(small_block),small_size); 9 printf("||\t大内存块数量:%d,每块占用%d字节,共%d字节\t||\n",BIGNUM,sizeof(big_block),big_size); 10 printf("||\t小内存管理块占用%d字节\t\t\t\t||\n",sizeof(small_block_manage)); 11 printf("||\t大内存管理块占用%d字节\t\t\t\t||\n",sizeof(big_block_manage)); 12 printf("||\t初始化时总共需申请%d字节的内存区域\t\t||\n",pre_alloc_size); 13 printf(" =========================================================\n"); 14
1可以看下截图 2

(2)对于超过1000字节的大内存块,从堆中申请,管理模式如下 ↓( 使用一个带有头结点的链表)

p_head为头,p_tail为尾

数据结构定义如下 ↓ 

1typedef struct{ 2 int * heap_add;/*记录从heap申请的内存块的地址 */ 3 int size;/*该首地址的内存区占用多少字节 */ 4 struct heap_add_node *next;/*指向下一个内存区域 */ 5}heap_add_node; 6
12.初始化部分  mem_init() 2

(1)初始化互斥信号量(防止多任务同时进行内存申请时进行)

(2)申请pre_alloc_size大小区域,用于1.(1),将每个内存块置为available。将整个内存块切分成 小内存块管理区域、大内存块管理区域、小内存块群、大内存块群 四个连续的区域。

将小内存块群切成SMALLNUM个SMALLSIZE大小的内存单元, 将大内存块群切成BIGNUM个BIGSIZE大小的内存单元。

(3)初始化管理从堆申请的链表。

3.申请地址 两个相关函数 

(1) mem_malloc中进行判断,用户需要的size字节大小内存从 小内存区域、大内存区域和堆内存区域 申请。 (与大小和内存区域占用情况相关)

(2) malloc_by_type从已经判断好的区域进行申请,每次占用一块完整的内存。如用户需要一块小于SMALLSIZE字节的内存块,实际占用的也还是SMALLSIZE字节。用牺牲内部碎片的方法减少外部碎片。

4.通过用户输入的首地址释放内存 mem_free()

(1) 通过大、小内存块管理区域使用for循环,遍历是否有 内存块的首地址 与 用户想要释放的首地址一致,有则释放,并更新内存管理区域的数据。

(2) 大、小内存块中未搜到,搜索 从堆申请的内存地址链 是否有该地址,有则释放,并且!释放存储该地址信息的结点。

(3) 均未搜到,该地址为无效首地址。

5.查看内存占用情况 mem_show()

(1) 通过大、小内存管理区域的值,展示内存占用情况。

(2) 遍历从堆申请的地址链表,展示内存占用情况。traverse_list()

6.退出程序时,释放包含大小内存块的pre_alloc_size大小部分区域,释放堆申请地址链。

7.将信号量相关部分注释掉后,可通过Dev C++等编译。查看一下效果↓

代码地址  https://github.com/crab0314/vxworks_mem

代码交流 2021