第6章 内存的动态分配

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

6.2 动态内存的管理(续)
查询一个内存分区的状态
OS_MEM *OSMemQuery( OS_MEM *pmem, OS_MEM_DATA *pdata ); // 待查询的内存控制块的指针 // 存放分区状态信息的结构的指针
OS_MEM_DATA结构如下:
typedef struct { void *OSAddr; void *OSFreeList; INT32U OSBlkSize; INT32U OSNBlks; INT32U OSNFree; INT32U OSNUsed; } OS_MEM_DATA; // 内存分区的指针 // 分区内内存块链表的头指针 // 内存块的长度 // 分区内内存块的数目 // 分区内空闲内存块的数目 // 已被分配的内存块的数目
六、内存的动态分配
东软IT人才实训中心
Copyright 3 Sept. 2008 Confidential
2008 By Neusoft Group. All rights reserved
1
第六章:内存的动态分配
目标: 本章旨在向学员介绍内存的数据结构及操 作,通过本章的学习,学员应该掌握如下 知识: uC/OS-II对内存的分区及分块 描述内存块的数据结构-内存控制块 内存控制块与内存分区之间的关系 对内存的操作
// 内存分区的指针 // 内存控制块链表的指针 // 内存块的长度 // 分区内内存块的数目 // 分区内当前可分配的内存块数目
内存
下一个内存块的指针 内存块1
下一个内存块的指针
内存块2
内存控制块OS_MEM
…… 下一个内存块的指针 …… 内存块n
内 存 分 区
0
从图中可知,内存控制块的内 存分区指针OSMemAddr指向了 内存分区,内存分区中的各个 内存块又组成了一个单向链表, 内存控制块的链表指针 OSMemFreeList就指向了这个 单向链表的头。
3 Sept. 2008 Confidential
6.2 动态内存的管理(续)
释放一个内存块
OS_MEM *OSMemPut( OS_MEM *pmem, void *pblk );
进入 no 返回OS_MEM_INVALID_PMEM 链表头指针OSMemFreeList 指向释放的内存块 Pmem->OSMemNFree++ 返回OS_NO_ERR
在内存控制块中 填写刚建立分区的信息
返回内存控制块指针pmem
yes
BlkSize != NULL?
no
yes
图6-4 函数OSSemCreate()流程图
返回
3 Sept. 2008 Confidential
例6-1
建立一个含有50个内存块并且每块的长度为64字节的内存分区。试 写出主要代码。
OS_MEM INT8U INT8U *CommTxBuffer; CommTxPart[50][64]; err; // 定义内存分区指针 // 定义分区和内存块
// 内存分区对应的内存控制块指针 // 错误信息
使指针OSMemFrereList指 向新的链表头
pmem != NULL?
yes
内存分区尚 存在未被分 配的内存块
pmem->OSMemFree>0?
yes Pblk=pmem->OSMemFreeList
将内存块链表的第一个块的 指针OSMemFrereList赋给了 指针pblk
学时:2.0学时
教学方法:讲授ppt+上机练 习+点评+案例分析
3 Sept. 2008 Confidential
6.1 内存控制块
应用程序在运行中为了某种特殊需要,经常需要临时获得一些内存空间。因 此作为比较完善的操作系统,必须具有动态分配内存的能力。 能否合理、有效的对内存进行分配和管理,是衡量一个操作系统品质的指标 之一。特别对于实时操作系统,应该保证系统在动态分配内存时,它的执行 时间必须是可确定的。
图6-5 函数OSSemGet()流程图
3 Sept. 2008 Confidential
例6-2
在例6-1的基础上写出任务MyTask请求一个内存块的代码。
OS_MEM INT8U INT8U INT8U *CommTxBuffer; CommTxPart[50][64]; err; *BlkPtr; // 定义内存分区指针 // 定义分区和内存块 // 定义内存块指针
3 Sept. 2008 Confidential
6.2 动态内存的管理(续)
请求获得一个内存块
OS_MEM *OSMemGet( OS_MEM *pmem, INT8U *err );
进入 no *err=OS_MEM_INVALID_PMEM 返回空指针NULL 调整区内的内存块链表 no *err=OS_MEM_NO_FREE_BLKS 返回空指针NULL Pmem->OSMemNFree-*err=OS_NO_ERR 返回分配给应用程序 的内存块指针pblk
ALeabharlann Baidudr != NULL?
yes
分区的内存块 至少有2块 每个内存块的 空间得至少能 存放一个指针
nblks > 1?
no
yes no
blksize >= sizeof(vois*)?
*err=OS_MEM_INVALID_SIZE 返回空指针NULL
*err=OS_MEM_INVALID_PART 返回空指针NULL
3 Sept. 2008 Confidential
6.1.1 可动态分配内存的划分
在内存中划分一个内存分区与内存块的方法: INT16U IntMemBuf[10][10];
uC/OS-II要求同一个分区中内存块的字节 数必须相等,而且每个分区与该分区内存 块的数据类型必须相同。
注意:上面这个定义只是在内存中划分出了分区及内存块的区域,还不是一个真正的 可以动态分配的内存区!
内存控制块的结构:
typedef struct{ void *OSMemAddr; void *OSMemFreeList; INT32U OSMemBlkSize; INT32U OSMemNBlks; INT32U OSMemNFree; }OS_SEM;
OSMemAddr OSMemFreeList OSMemBlkSize OSMemNBlks OSMemNFree
图6-2 内存控制块与内存分区和内存块的关系2-有控制块时的分区
3 Sept. 2008 Confidential
6.1.3 空内存控制块链表
uC/OS-II初始化时,会调用内存初始化函数OS_MemInit()定义并初始化一个空 内存控制块链表。 每当应用程序需要创建一个内存分区时,系统就会从空内存控制块链表中摘 取一个控制块,而把链表的头指针OSMemFreeList指向下一个空内存控制块;而 每当应用程序释放一个内存分区时,则会把该分区对应的内存控制块归还给空 内存控制块链表。
内存
内存块1 内存块2 内存块3 …… …… 内存块n
内 存 分 区
图6-1 内存控制块与内存分区和内存块的关系1-没有控制块时的分区
只有当把内存控制块与分区关联起来之后,系统才能对其进行相应的管理和 控制。它才是一个真正的动态内存区。
3 Sept. 2008 Confidential
6.1.2 内存控制块OS_SEM的结构
图6-6 函数OSSemPut()流程图
3 Sept. 2008 Confidential
例6-3
设计一个含有一个任务的应用程序,该任务负责打印两个起始显示 位置不同的相同字符串。要求在任务中申请一个内存块,并把存放 字符串显示起始位置的数据变量定义在该内存块中。
3 Sept. 2008 Confidential
0
共OS_MAX_MEM_PART个空内存控制块
图6-3 空内存控制块链表
在OS-CFG.H中定义的常数
3 Sept. 2008 Confidential
6.2 动态内存的管理
创建动态内存分区
OS_MEM *OSMemCreate( void *addr, INT32U nblks, INT32U blksize, INT8U *err );
void main(void) { INT8U err; …… OsInit(); …… CommTxBuffer = OSMemCreate(CommTxPart,50,64,*err); …… OSStart(); 需要注意的是:应用程序在调用函数OSMemGet()时, } 应该事先知道该分区中内存块的大小,并且在使用该 内存块时不能超其长度,否则会引起灾难性的后果。 void MyTask( (void *)pdata ) 当应用程序不再需要该内存块时,必须及时将其释放。 { …… for(;;){ …… BlkPtr = OSMemGet(CommTxBuffer,&err); …… } }
void main(void) { INT8U err; …… OsInit(); …… CommTxBuffer = OSMemCreate( CommTxPart, 50, 64, *err …… OSStart(); } );
// 内存分区的首地址 // 分区内内存块的数目 // 每个内存块的长度
OSMemFreeList
OSMemAddr OSMemFreeList OSMemBlkSize OSMemNBlks OSMemNFree
OSMemAddr OSMemFreeList OSMemBlkSize OSMemNBlks OSMemNFree
OSMemAddr OSMemFreeList OSMemBlkSize OSMemNBlks OSMemNFree
// 内存所属内存分区的指针 // 待释放内存块的指针
pmem != NULL?
yes
pblk != NULL?
no
返回OS_MEM_INVALID_PBLK
yes
需要注意的是,在调用函数OSMemPut()时,一定要 确保把该内存块释放到它原来所属的内存分区中, 否则会引起灾难性后果。 对例6-2中任务MyTask使用的内存块进行释放
uC/OS-II改进了ANSI C用来动态分配和释放内存的函数malloc()和free(),使他 们可以对大小固定的内存进行操作,从而使函数malloc()和free()执行时间成为 可确定的,满足了实时操作系统的要求。 uC/OS-II对内存进行两级管理:把连续内存分成若干个分区,每个分区又分 成若干个大小相等的内存块来进行管理。 在ANSI C中可以用malloc()和
练习6-1
设计一个有两个任务的应用程序,其中一个任务用来进行两个随机数的加 法运算,另一个任务则用来显示结果,要求加法运算的和存放在动态内存中。
3 Sept. 2008 Confidential

free()两个函数动态地分配内存和 释放内存。但是,在嵌入式实时操 操作系统以分区为单位来管理动态内存,而任务以内存块为单位来获得和释 作系统中,多次这样做会把原来很 放动态内存。 大的一块连续内存区域,逐渐地分 割成许多非常小而且彼此又不相邻 内存分区及内存块的使用情况由内存控制块来记录。 的内存区域,也就是内存碎片。由 于这些碎片的大量存在,使得程序 到后来连非常小的内存也分配不到
3 Sept. 2008 Confidential
例6-4
设计一个含有3个任务的应用程序,这3个任务分别是MyTask、YouTask和 HerTask。在应用程序中创建一个动态内存分区,该分区有8个内存块,每个内 存块的长度为6个字节。应用程序的任务YouTask和HerTask都在任务运行后请求 一个内存块,随后就释放它。任务MyTask也在任务运行后请求一个内存块,但 是要在任务MyTask运行6次后,才释放它所申请的内存块。 为了了解内存分区变化的情况,编写代码来观察分区头指针和已被使用内 存块的个数。
进入 no *err=OS_MEM_INVALID_ADDR 返回空指针NULL *err=OS_MEM_INVALID_BLKS 返回空指针NULL 自空内存控制块链表 取一个空内存控制块 将分区中的所有内存 块链接为单向链表
// 内存分区的起始地址 // 分区中内存块的数目 // 每个内存块的字节数 // 错误信息
相关文档
最新文档