堆栈,是我们常常会听说过的词汇。搞嵌入式如果说不懂得堆栈可能会被怀疑学习了一个假的嵌入式。不过,坦白来说,我还是不太理解其中的细节,比如说栈的位置在哪?我们说栈是先进后出FILO形式的数据结构,堆是先进FIFO先出的形式的数据结构。栈是由系统操作的,而堆是由程序员操作的。我感觉这些解释都是玄而又玄的说法,我现在还没有理清头绪,以后有具体头绪了再来写出我的想法。现在先学习大佬的想法:
栈
- 栈经常与 sp 寄存器(译者注:"stack pointer",了解汇编的朋友应该都知道)一起工作,最初 sp 指向栈顶(栈的高地址)。
- CPU 用 push 指令来将数据压栈,用 pop 指令来弹栈。当用 push 压栈时,sp 值减少(向低地址扩展)。当用 pop 弹栈时,sp 值增大。存储和获取数据都是 CPU 寄存器的值。
- 当函数被调用时,CPU使用特定的指令把当前的 IP (译者注:“instruction pointer”,是一个寄存器,用来记录 CPU 指令的位置)压栈。即执行代码的地址。CPU 接下来将调用函数地址赋给 IP ,进行调用。当函数返回时,旧的 IP 被弹栈,CPU 继续去函数调用之前的代码。
- 当进入函数时,sp 向下扩展,扩展到确保为函数的局部变量留足够大小的空间。如果函数中有一个 32-bit 的局部变量会在栈中留够四字节的空间。当函数返回时,sp 通过返回原来的位置来释放空间。
- 如果函数有参数的话,在函数调用之前,会将参数压栈。函数中的代码通过 sp 的当前位置来定位参数并访问它们。
- 函数嵌套调用和使用魔法一样,每一次新调用的函数都会分配函数参数,返回值地址、局部变量空间、嵌套调用的活动记录都要被压入栈中。函数返回时,按照正确方式的撤销。
- 栈要受到内存块的限制,不断的函数嵌套/为局部变量分配太多的空间,可能会导致栈溢出。当栈中的内存区域都已经被使用完之后继续向下写(低地址),会触发一个 CPU 异常。这个异常接下会通过语言的运行时转成各种类型的栈溢出异常。(译者注:“不同语言的异常提示不同,因此通过语言运行时来转换”我想他表达的是这个含义)
堆
https://blog.youkuaiyun.com/henryzhang2009/article/details/44863295具体内容可以参看这个博客
不过在本次的内容中,不对栈做研究,只讨论堆的话题。例如:在RT-Thread下堆是怎么使用的?以及如何从xx.map中获取有关数据?
/* 线程入口 */
void thread1_entry(void *parameter)
{
int i;
char *ptr = RT_NULL; /* 内存块的指针 */
char a = 40,b = 40,flag; //堆空间申请,所支持两个参数
for (i = 0; ; i++)
{
if(i == 0)
{
ptr = rt_malloc(1);
rt_kprintf("malloc get memory :%d byte\n", 1);
flag = 0;
}
/* 每次分配 (1 << i) 大小字节数的内存空间 */
ptr = rt_realloc(ptr,1 << i);
// ptr = rt_malloc(1 << i);
/* 如果分配成功 */
if (ptr != RT_NULL)
{
if(flag == 0)
rt_kprintf("rt_malloc get memory :%d byte\n", (1 << i));
else
rt_kprintf("rt_realloc 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;
}
rt_thread_mdelay(1000);
rt_free(ptr);
}
// ptr = rt_calloc(a,b);
// if(ptr != RT_NULL)
// {
// rt_kprintf("rt_calloc get memory : %d byte\n",a*b);
// rt_free(ptr);
// rt_kprintf("free memory :%d byte\n",a*b);
// }
// else
// {
// rt_kprintf("Failed to try to get %d byte\n",a*b);
// return ;
// }
}
内存的申请函数:
rt_malloc(xx);
rt_realloc(xx,xx);
rt_calloc(xx,xx);
内存的删除函数:
rt_free(xx);
在学习过程中,有一个初步接触得东西xx.map文件
双击这个,就可以得到rtthread-stm32.map的文件。
RO RW ROM的具体意义
Program Size: Code=908 RO-data=320 RW-data=0 ZI-data=1024
Code:指代码的大小;
Ro-data:指除了内联数据(inline data)之外的常量数据;
RW-data:指可读写(RW)、已初始化的变量数据;
ZI-data:指未初始化(ZI)的变量数据;
Code、Ro-data:位于FLASH中;
RW-data、ZI-data:位于RAM中;
提醒:RW-data已初始化的数据会存储在Flash中,上电会从FLASH搬移至RAM中。
map文件的具体意义,请参看:
http://blog.youkuaiyun.com/ybhuangfugui/article/details/75948282