栈(stack): 由编译器自动分配和释放
堆(heap) : 一般由程序员分配和释放
int a = 0; // 全局初始化区
char *p1; // 全局未初始化区
main() {
/************ 定义的这些局部变量所占用的空间都来源于**栈空间** , 当这个**函数运行完**结束之后 , 这些局部变量占用的**栈内存空间**就会**被释放**掉 *************/
int b; // 栈
char s[] = "abc"; // 栈
char *p2; // 栈
char *p3 = "123456"; // 123456\\0在常量区,p3在栈上
static int c =0; // 全局(静态)初始化区
/*********** 通过C语言内存函数所得到的内存空间来源于**堆空间** *************/
p1 = (char *)malloc(10); // 堆
p2 = (char *)malloc(20); // 堆
}
裸机动态内存配置和使用
Libraries\CMSIS\Device\ST\STM32F1xx\Source\Templates\arm\startup_stm32f103xe.s
// **栈空间**的设置
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
// **堆空间**的设置
Heap_Size EQU 0x00000200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
target\libraries\gd32_lib\CMSIS\GD\GD32F4xx\Source\ARM\startup_gd32f4xx.s 注意:使用的是GCC下面的.s文件,不是ARM下的.s文件
// **栈空间**的设置
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
// **堆空间**的设置
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
在裸机中,设置完堆栈空间之后,就可以通过C语言标准函数 malloc 去分配相应的动态内存,使用完之后,通过C语言标准函数 free 去释放相应的动态内存
例如:
char *p;
p = (char*)malloc(10); // 分配动态内存
......
free(p); // 释放动态内存
RT-Thread 系统动态内存的配置和使用
drivers\board.c
/**
* This function will initial STM32 board.
*/
void rt_hw_board_init(void)
{
HAL_Init();
SystemClock_Config();
#ifdef RT_USING_HEAP
rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
......
}
target\board\board.c
void bsp_early_initialize(void)
{
......
// 初始化**系统动态内存堆**(定义**可用RAM**区域)
rt_system_heap_init((void*)SYSTEM_FREE_MEM_BEGIN, (void*)SYSTEM_FREE_MEM_END);
......
}
在RT-Thread系统中,设置完堆栈空间之后,就可以通过RT-Thread系统中特定的函数 rt_malloc 去分配相应的动态内存,使用完之后,通过 rt_free 去释放相应的动态内存
例如:
char *p;
p = (char*)rt_malloc(10); // 分配**动态内存**
......
rt_free(p); // 释放**动态内存**
rt_malloc 分配动态内存空间的时候,会有两个结果,一个是成功,一个是失败
rt_malloc 函数就会返回 RT_NULL< 系统所拥有的空闲空间 的时候 才能分配成功,否则的话会分配失败RT-Thread 系统动态内存配置的函数
rt-thread\src\mem.c
/**
* @ingroup SystemInit 初始化系统堆内存 (堆[heap]: 一般由程序员分配和释放)
*
* 该函数用于**初始化**系统**堆内存管理模块**,将**指定**的**内存区域**划分为**堆内存**,并**建立**初始**内存块**结构
* 堆内存管理采用链表结构,支持动态内存分配与释放,同时通过信号量保证线程安全
*
* 用于从SRAM分出(动态内存空间)
*
* @param begin_addr 堆内存起始地址(需要按RT_ALIGN_SIZE对齐)
* @param end_addr 堆内存结束地址(需要按RT_ALIGN_SIZE向下对齐)
*/
void rt_system_heap_init(void *begin_addr, void *end_addr)
{
......
}
rtos\rt-thread\src\mem.c
void rt_system_heap_init(void *begin_addr, void *end_addr)
{
......
}
先给系统配置好动态内存空间占用的区域,然后再去使用它
如果整个芯片没有外部的RAM的话,那就把片内的RAM拿来当系统的动态内存空间使用
如果芯片的外部空间有外扩RAM,还可以把芯片的外扩RAM拿来当系统的动态内存空间使用
只需要换掉,这段空间的 begin_addr 和 end_addr 就行
动态内存使用过程中要注意的问题
内存复位
避免内存泄漏
rt_malloc 需要和 rt_free 配套使用char *p;
p = (char*)rt_malloc(10); // 申请长度为 10 Bytes 的动态内存空间
// 判断是否申请成功
if(p != RT_NULL) {
rt_memset(p,0,10); // 对动态内存进行清0操作(**内存复位**)
......
}
rt_free(p); // 释放动态内存(**避免内存泄漏**)
其他动态内存相关API
在已分配内存块的基础上重新分配内存块的大小(增加或缩小),在进行重新分配内存块时,原来的内存块数据保持不变(缩小的情况下, 后面的数据被自动截断)
比如之前分配了50个字节的动态内存空间,可是在后面的使用中发现,50个字节的内存空间不够用,想要加大到100个字节
void *rt_realloc(void *rmem, rt_size_t newsize) // 只需要1个形参:newsize
从内存堆中分配连续内存地址的多个动态内存块
分配 count 个 size 字节大小的连续内存地址的动态内存块
void *rt_calloc(rt_size_t count, rt_size_t size) // 需要两个形参