RTX——第18章 内存管理
以下内容转载自安富莱电子: http://forum.armfly.com/forum.php
内存管理介绍
在 ANSI C 中,可以用 malloc()和 free()2 个函数动态的分配内存和释放内存,但是,在嵌入式实时
操作系统中,调用 malloc()和 free()却是危险的,因为多次调用这两个函数会把原来很大的一块连续内场
区域逐渐地分割成许多非常小而且彼此又不相邻的内存块,也就是内存碎片。由于这些内存碎片的大量存
在,使得程序到后来连一段非常小的连续内存也分配不到。另外,由于内存管理算法上的原因,malloc()
和 free()函数的执行时间是不确定的。
在 RTX 中,操作系统把连续的大块内存按分区来管理。每个分区中包含整数个大小相同的内存块。如
图 18.1 所示:
利用这种机制,就可以得到和释放固定大小的内存块。 这样内存的申请和释放函数的执行时间就是确定的了。
在一个系统中可以有多个内存分区,这样,应用程序就可以从不同的内存分区中得到不同大小的内存
块。但是特定的内存块在释放时,必须重新放回到它以前所属于的内存分区。显然,采用这样的内存管理
算法,上面的内存碎片文件就得到了解决。
其实 RTX 的内存管理也非常好理解,可以理解成一个二维数组,比如我们定义一个二维数组为:
uint8_t mpool[10][32]。 对应到 RTX 的内存管理上就是定义了 10 个内存块,每块大小是 32 字节。
如果还需要其它大小的内存块,还可以多定义几个其它大小的。
内存管理 API 函数
使用如下 7 个函数可以实现 RTX 的内存管理:
_declare_box
_declare_box8
_init_box
_init_box8
_alloc_box
_calloc_box
_free_box
函数_declare_box
函数原型:
#define _declare_box( \
pool, \ /* 内存池变量名 */
size, \ /* 内存块大小,单位字节 */
cnt ) \ /* 内存池中内存块的个数 */
U32 pool[((size+3)/4)*(cnt) + 3]
函数描述:
函数_declare_box 用于定义一块内存池。
第 1 个参数填写内存池的变量名。
第 2 个参数填写内存块的大小,单位字节。
第 3 个参数填写内存池中内存块的个数。
使用这个函数要注意以下问题:
1. 宏定义中通过操作(size+3)/4 保证了每个内存块大小是 4 字节的倍数,从而也就保证了每个内存块
的首地址是 4 字节对齐的(4 字节对齐的含义是地址对 4 求余等于 0)。这里初学者也要注意数据类
型的字节对齐问题。
基本数据类型的字节对齐问题
这个问题在 MDK5 安装目录里面的文档 DUI0375G_02_mdk_armcc_user_guide.pdf 里面有详细的说明,
简单的说明, 数据类型有几个字节, 那么这个数据类型的变量就是几字节对齐,比如 32 位的 int 型
有 4 个字节,那么此 int 型定义的变量就是 4 字节对齐,对于初学者要牢牢的记住这个知识点。
其实这个在keil的帮助文档里面就有,善于利用ide的帮助文档,这是最直接快捷的熟悉编译器的方式。
2. 内存池中额外定义的 12 个字节用于将内存块做指针链表,方便动态的申请和释放。
函数_declare_box8
函数原型:
#define _declare_box8( \
pool, \ /* 内存池变量名 */
size, \ /* 内存块大小,单位字节 */
cnt ) \ /* 内存池中内存块的个数 */
U64 pool[((size+7)/8)*(cnt) + 2]
函数描述:
函数_declare_box 用于定义一块内存池。
第 1 个参数填写内存池的变量名。
第 2 个参数填写内存块的大小,单位字节。
第 3 个参数填写内存池中内存块的个数。
使用这个函数要注意以下问题:
1. 宏定义中通过操作(size+7)/8 保证了每个内存块大小是 8 字节的倍数,从而也就保证了每个内存块
的首地址是 8 字节对齐的(8 字节对齐的含义是地址对 8 求余等于 0)。这里初学者也要注意数据类
型的字节对齐问题。
2. 内存池中额外定义的 16 个字节用于将内存块做指针链表,方便动态的申请和释放。
函数_init_box
函数原型:
int _init_box (
void* box_mem, /* 内存池首地址 */
U32 box_size, /* 内存池大小,单位字节 */
U32 blk_size ); /* 内存块大小, 单位字节 */
函数描述:
函数_init_box 用于内存池的初始化,初始化时用到的参数都是源自于_declare_box。
第 1 个参数填写内存池的首地址。
第 2 个参数填写内存池的大小,单位字节。
第 3 个参数填写内存块大小,单位字节。
使用这个函数要注意以下问题:
1. 强烈建议跟函数_declare_box 一起使用。用户不要自己去初始化这个函数,用_declare_box 声明的
才是最保险的。
2. 如果用户没有使用函数_declare_box 进行定义,那么要保证内存池首地址是 4 字节对齐的。
3. 如果用户没有使用函数_declare_box 进行定义,那么要保证内存池的大小 box_size 至少有 12 个字节,
因为这个 12 个字节是用于将内存块做成指针链表,方便动态申请和释放。
函数_init_box8
函数原型:
int _init_box (
void* box_mem, /* 内存池首地址 */
U32 box_size, /* 内存池大小,单位字节 */
U32 blk_size ); /* 内存块大小, 单位字节 */
函数描述:
函数_init_box8 用于内存池的初始化,初始化时用到的参数都是源自于_declare_box8。
第 1 个参数填写内存池的首地址。
第 2 个参数填写内存池的大小,单位字节。
第 3 个参数填写内存块大小,单位字节。
使用这个函数要注意以下问题:
1. 强烈建议跟函数_declare_box8 一起使用。用户不要自己去初始化这个函数,用_declare_box 声明的
才是最保险的。
2. 如果用户没有使用函数_declare_box8 进行定义,那么要保证内存池首地址是 8 字节对齐的。
3. 如果用户没有使用函数_declare_box8 进行定义,那么要保证内存池的大小 box_size 至少有 16 个字
节,因为这个 16 个字节是用于将内存块做成指针链表,方便动态申请和释放。
函数_alloc_box
函数原型:
void *_alloc_box (
void* box_mem ); /* 内存池的首地址 */
函数描述:
函数_alloc_box 用于从首地址是 box_mem 的内存池中申请一个内存块。
第 1 个参数填写内存池的首地址。
使用这个函数要注意以下问题:
1. 调用此函数前,一定要使用函数_init_box 或者_init_box8 进行初始化。
2. 函数_alloc_box 支持重入,而且是线程安全的,也即是说用户可以没有限制的在主函数和中断中调用此函数。
函数_free_box
函数原型:
int _free_box (
void* box_mem, /* 内存池首地址 */
void* box ); /* 要释放的内存块首地址 */
函数描述:
函数_free_box 用于释放使用函数_alloc_box 申请的内存块。
第 1 个参数填写内存池的首地址。
第 2 个参数填写要释放的内存块首地址。
使用这个函数要注意以下问题:
1. 此函数的第二个参数必须要填写正确,也就是用户使用的时候最好配套_alloc_box 一起使用。
2. 函数_free_box 支持重入,而且是线程安全的,也即是说用户可以没有限制的在主函数和中断中调用此函数。
代码练兵场:
串口打印:
这里有两点需要说明:
第一,为什么按键按下之后,先打印消息队列的输出,因为消息处理任务优先级高于按键处理任务(如果按键处理任务优先级高于消息处理,就会先打印按键消息);
第二,在下面函数中采用官方demo的方式:
我们可以使用void *pMsg,然后在wait中给&pMsg,最后打印的时候转换成自己想要的类型,也可以:
直接给出想要的类型在wait函数中强转,安富莱就是使用的后者。
RTX——第18章 内存管理的更多相关文章
- 【翻译】《深入解析windows操作系统第6版下册》第10章:内存管理
[翻译]<深入解析windows操作系统第6版下册>第10章:内存管理(第一部分) [翻译]<深入解析windows操作系统第6版下册>第10章:内存管理(第二部分) [翻译] ...
- Objective-C 基础教程第九章,内存管理
目录 Object-C 基础教程第九章,内存管理 前言: 对象生命周期 引用计数 RetainCount1项目例子 对象所有权 访问方法中的保留和释放 自动释放 所有对象放入池中 自动释放池的销毁时间 ...
- JZ2440 裸机驱动 第7章 内存管理单元MMU
本章目标: 了解虚拟地址和物理地址的关系: 掌握如何通过设置MMU来控制虚拟地址到物理地址的转化: 了解MMU的内存访问权限机制: 了解TLB.Cache.Write ...
- 【译】x86程序员手册13-第5章 内存管理
Chapter 5 Memory Management 内存管理 The 80386 transforms logical addresses (i.e., addresses as viewed b ...
- 第七章 内存管理单元MMU介绍
7.1 内存管理单元MMU介绍 7.1.1 S3C2410/S3C2440 MMU特性 负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查 特性: 与ARM V4兼容的映射长度.域.访问权 ...
- C#高级编程9 第14章 内存管理和指针
C#高级编程9 内存管理和指针 后台内存管理 1) 值数据类型 在处理器的虚拟内存中有一个区域,称为栈,栈存储变量的浅副本数据,通过进入变量的作用域划分区域,通过离开变量的作用域释放. 栈的指针指向栈 ...
- [学习笔记—Objective-C]《Objective-C-基础教程 第2版》第九章 内存管理
内存管理: 确保在须要的时候分配内存,在程序运行结束时释放占用的内存 假设仅仅分配内存而不释放内存,则会发生内存泄漏(leak memory),程序的内存占用量不断添加.终于会被耗尽并导致程序崩溃. ...
- 重读金典------高质量C编程指南(林锐)-------第七章 内存管理
2015/12/10补充: 当我们需要给一个数组返回所赋的值的时候,我们需要传入指针的指针.当我们只需要一个值的时候,传入指针即可,或者引用也可以. 结构大致如下: char* p = (char*) ...
- 【读书笔记】C#高级编程 第十四章 内存管理和指针
(一)后台内存管理 1.值数据类型 Windows使用一个虚拟寻址系统,该系统把程序可用的内存地址映射到硬件内存中的实际地址,该任务由Windows在后台管理(32位每个进程可使用4GB虚拟内存,64 ...
随机推荐
- SDUT 1157-小鼠迷宫问题(BFS&DFS)
小鼠迷宫问题 nid=24#time" title="C.C++.go.haskell.lua.pascal Time Limit1500ms Memory Limit 65536 ...
- jquery实现下拉联动
很多项目用到这个功能,虽然写了不下5次以上了,一直没做过记录,记录一下,下次直接拷贝了,免得还得要重复写浪费时间. 先上HTML代码: 品牌: <select class="sa&qu ...
- Eclipse c++ 编译调试
直接添加源文件方法: 右键选择工程->import->General->File System,在弹出的对话框中选择源文件目录,筛选文件后: 1.如果直接加到工程中,点Finish就 ...
- 速度挑战 - 2小时完成HTML5拼图小游戏
概述 我用lufylegend.js开发了第一个HTML5小游戏——拼图游戏,还写了篇博文来炫耀一下:HTML5小游戏<智力大拼图>发布,挑战你的思维风暴. 详细 代码下载:http:// ...
- 开源大数据技术专场(下午):Databircks、Intel、阿里、梨视频的技术实践
摘要: 本论坛第一次聚集阿里Hadoop.Spark.Hbase.Jtorm各领域的技术专家,讲述Hadoop生态的过去现在未来及阿里在Hadoop大生态领域的实践与探索. 开源大数据技术专场下午场在 ...
- Linux查看GPU信息和使用情况
Linux查看显卡信息: lspci | grep -i vga 使用nvidia GPU可以: lspci | grep -i nvidia [root@gpu-server-002 ~]# lsp ...
- iOS中的#import和class区别
在ios中我们经常会在.h和.m中引入一些类啊等等一般用的是#import来进行声明,你们可能也见到在.h文件进用@class来声明的,那么#import和@class进行声明 到底有什么的区别呢?下 ...
- JSEclipse—Eclipse上的JavaScript开发工具
http://blog.csdn.net/qiaogang2003/article/details/3035056原来js开发仅仅使用ue,不过开发效率比较低下. 找到一个Eclipse下的js开发工 ...
- 房产地图google map的初步应用点滴.1)(转)
房产地图google map的初步应用点滴.1)房产地图google map的初步应用点滴.2)房产地图google map的初步应用点滴.3) 房产地图google map的初步应用点滴.4) 以前 ...
- bootstrap table 插件 搜索
以前用过easyui datagrid 每次搜索的时候调用datagrid构造方法 重新获取数据, 发现bootstrap-table 插件不行,只需要初始化一次, 以后每次搜索时,直接调用refre ...