简述堆栈
栈(stack)
由编译器自动分配释放
堆(heap)
一般由程序员分配和释放
int a = 0; /* 全局初始化区 */
char *p1; /* 全局未初始化区 */
main()
{
int b; /* 栈 */
char s[] = "abc"; /* 栈 */
char *p2; /* 栈 */
char *p3 = "123456"; /* 123456 在常量区,p3 在栈上 */
static int c = 0; /* 全局(静态)初始化区 */
p1 = (char*)malloc(10); /* 堆 */
p2 = (char*)malloc(20); /* 堆 */
}
MDK 裸机系统动态内存配置和使用
; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x400;
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x200;
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
该程序中,分别设置了栈空间和堆空间,在设置了堆空间之后就可以通过C 语言标准函数分配动态内存,并可通过free 释放动态内存
这有一段简短的程序告诉你为什么要建立动态内存以及建立动态内存的好处
p = (char*)malloc(10);
free(p);
RT-Thread 动态内存配置和使用
在RT-Thread 中使用动态内存需要先有一个动态函数帮我们配置好动态内存。
rt_system_heap_init((void*)HEAP_BEGIN,(void*)HEAP_END);
HEAP_BEGIN = (void*)&Image$$RW_IRAM1$$ZI$$Limit
HEAP = 0x20000000 + STM32_SRAM_SIZE * 1024
rt_system_heap_init
此函数的作用是以HEAP_BEGIN
为起始地址,HEAP_END
为结束地址分配一段动态地址。
Image$$RW_IRAM1$$ZI$$Limit
是一个链接器导出的符号,代表ZI 段的结束,也就是程序执行区的RAM 结束后的地址,反过来也就是我们执行区的RAM 未使用的区域的起始地址,即我们所定义的全局变量、静态变量以外的区域的起始地址。
Total RW + heap size = MCU total RAM size
有了动态内存分配之后便可通过RT-Thread 中rt_malloc
和rt_free
的配合使用来获得和释放动态内存
(其与C 语言的malloc
和 free
相对应)
p = (char*)rt_malloc(10);
rt_free(p);
代码示例:
void thread1_entry(void *parameter)
{
int i;
char *ptr = RT_NULL; /* 内存块的指针 */
for (i = 0; ; i++)
{
/* 每次分配 (1 << i) 大小字节数的内存空间 */
ptr = rt_malloc(1 << i);
/* 如果分配成功 */
if (ptr != RT_NULL)
{
rt_kprintf("get memory :%d byte\n", (1 << i));
/* 释放内存块 */
rt_free(ptr);
rt_kprintf("free memory :%d byte\n", (1 << i));
ptr = RT_NULL;
}
else
{
rt_kprintf("try to get %d byte memory failed!\n", (1 << i));
return;
}
}
}
动态内存堆使用注意点
内存复位
当我们每次申请到新的内存块之后,建议对所申请到的内存块进行清零操作。
因为程序空间是公用的,当我们申请了一块内存块后,此内存块可能含有遗留信息,初始值不一定为零,故申请到内存块空间后建议清零。
程序实现:
int *p = rt_malloc(10); /* 申请一段内存空间 */
if(p != RT_NULL) /* 若申请成功 */
{
rt_memset(p, 0, 10); /* 将从p 开始的10个字节内存空间写0 */
}
内存泄漏
内存泄漏(Memory Leak)是指程序中已动态分配的堆由于某种原因,程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果
注意:在使用动态内存时应将rt_malloc
和rt_free
配套使用
其他动态内存相关API
void *rt_realloc(void *rmem, rt_size_t newsize)
在已分配内存块的基础上重新分配内存块的大小(增加或缩小)
在进行重新分配内存块时,原来的内存块数据保持不变(缩小的情况下,后面的数据被自动截断)
void *rt_calloc(rt_size_t count, rt_size_t size)
从内存堆中分配连续内存地址的多个内存块
普通的全局变量或静态变量一旦申请,即整个程序的执行过程中都是占用内存的,即使清零。
而若我们申请动态内存来放置变量,当我们将这段动态内存释放后,这块内存上面就是真的没有东西了,输出这块内存上的信息,什么都得不到。