一个由C/C++编译的程序占用的内存分为以下几个部分:
1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。所以在局部变量中尽量不要使用大数组,容易造成栈溢出。
2、堆区(heap): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。
3、全局区(静态区static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 ( 程序结束后由系统释放)
4、文字常量区:常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区:存放函数体的二进制代码
更详细的解释:https://www.cnblogs.com/yechanglv/p/6941993.html
动态内存分配使用的是堆区,所以我们更关注是堆区,别的交给编译器就好了。
在启动文件有如下定义(以STM32F103XE为例):
仿真代码:代码下载地址
堆区和栈区的大小在如下位置定义,可以按自己的需要修改,注意单片的RAM的大小,堆和栈不是你想改多大就多的。
首先要把使用rt-thread的动态内存的宏定义打开(某些情况下是注释的),,这样才能使用rt-thread的动态内存管理功能,如下图:
这时,rt-thread就开启了动态管理的功能,初始化代码如下:
该代码赋予了rt-thread管理动态内存(堆)的权限。
其中,HEAP_BEGIN定义:
#define HEAP_BEGIN ((void *)&Image$$RW_IRAM1$$ZI$$Limit)
其中:
Image$$RW_IRAM1$$ZI$$Limit
是一个链接器导出的符号,代表ZI段的结束,也就是程序执行区的RAM结束后的地址,反过来也就是我们执行区的RAM未使用的区域的起始地址,将这一部分作为我们OS管理的堆的起始地址。
HEAP_END定义:
#define HEAP_END STM32_SRAM_END
#define STM32_SRAM_END (0x20000000 + STM32_SRAM_SIZE * 1024) //0x20000000为该单片机内部RAM的
//起始地址
#define STM32_SRAM_SIZE 64 //该单片机的RAM为64K
也就是说HEAP_END就是该单片机的RAM的结束地址。
总结一下,这个初始化函数就是将地址从HEAP_BEGIN到HEAP_END之间的空间作为OS管理的堆空间。
1、获取动态内存:
void *rt_malloc(rt_size_t size)
入口参数为字节数,失败则返回RT_NULL,最好使用类似如下的语句判断是否获取内存成功:
/* 分配 512字节数的内存空间 */
ptr = rt_malloc(512);
/* 如果分配成功 */
if (ptr != RT_NULL)
{
//此处使用ptr
}
2、释放获取的内存:
void rt_free(void *rmem)
rt_free(ptr); //使用举例,对应上文
入口参数为要释放的空间的指针,切记,分配了就要要对应的释放,否则会造成内存泄露,甚至系统崩溃。
1、内存复位
每次新申请的内存块,建议对内存块进行清零操作(因为之前的内存块可能被分配存在一些无意义的数据),使用如下操作:
rt_memset(ptr,0,512); //ptr对应上文已分配内存的指针
2、内存泄露
分配的内存使用完后要及时清理,rt_malloc和rt_free要成双成对使用。内存泄露后果严重,轻则造成系统变得缓慢,重则造成系统崩溃。
自行查找官方API手册。
1、使用rt-thread的动态内存管理比直接使用C语言带的malloc的优势何在?
2、源码分析
3、理解错的地方