嵌入式C语言的堆栈管理怎样实现
首先,堆栈的问题和有没有操作系统没有必然关系。很多操作系统的确会在内存管理的问题上插手很多,其主要是为了多线程间合理的共享内存。这其实是题主问题在多线程环境下的引申。在C语言中栈的进出是靠大括号完成的。编译器会把大括号翻译成对应的机器码来完成出入栈。栈的操作比较简单机械,所以C语言可以简单的把它用大括号表示。至于堆,其实也很简单,只是在内存中指定一个区域作为共享的内存空间,而每次malloc的时候,会在一个记录表上记录上哪个内存位置已经分配了出去,每次free的时候再把这条记录抹去。这样就可以知道分配了哪些内存位置,还有哪些内存位置可以用。这个逻辑也很简单,用C语言就可以实现。但这里有个比较麻烦的问题,就是内存碎片。因为堆的创建和销毁是随机的,因此当一个1024字节的内存,分配了两个不连续的256字节空间后,虽然还剩下512字节的空闲内存,但因为其不连续,你是无法malloc请求一个512字节的堆的。这种问题会造成内存极大的浪费。为了解决这个问题,提出了一种叫做内存分页的思想。大概意思就是,将物理内存按照固定大小,比如4kb,将物理内存分成若干个“页”。当你申请一块内存区域的时候,比如10k,内存管理的代码会寻找出空闲的3个页,这三个页并不一定物理连续,比如1,3,8号页,然后给他分配一个虚拟的内存地址,返回给你。在你看来,你得到的是一个连续的10kb空间,但其实他背后是3块不连续的页。这时候问题来了,当你在这个空间写入数据的时候,需要将你的连续内存操作映射到这三个不连续的空间中,这时候操作的效率一定会下降,因为你总得将虚拟内存地址转化为物理内存地址。为了解决这个效率问题,硬件上加入了内存管理单元MMU。MMU通过硬件来完成虚拟内存地址到物理内存地址的映射,这样就不会消耗CPU的时间了。在CPU看来,就好象自己在操作一块连续内存一样。很多MCU是没有MMU的,所以一般在这类嵌入式上尽量不要使用堆,否则内存浪费会很严重。在以上这些概念的基础上,很多操作系统还增加了虚拟内存的概念,就是将硬盘用来作为内存使用。这里边也会有分页的概念,而这里的分页就需要操作系统通过软件的方式来提供了,因为虚拟内存地址背后对应的不仅是物理内存,还有硬盘上的空间。内存管理的目的主要就是在多任务且任务对内存使用预见性差的情况下,通过较为底层的软件和硬件设施,最大化内存的使用率和访问效率,减少内存浪费。顺着这条思路,在网上搜索一下,你就会知道所有关于内存管理的问题了。
■网友
首先要明白,C语言运行的基本环境就是要有堆栈,因为C语言函数调用、函数内变量、参数的传递都是保存到堆栈空间。研究嵌入式启动流程,你会发现,在系统上电后,在跳入第一个C语言函数之前,必须要初始化栈空间的(初始化RAM后,给栈指针寄存器赋初值)。
一般来讲,函数内的局部变量、需要传递的参数,都是保存在栈内的。一个函数可以多层级调用函数,每调用一层函数,都有一个基本的栈帧,保存当前函数的局部变量、参数、临时变量等。每个栈帧都会依次放到栈空间,形成一个回溯链表结构(每个栈帧会有一个成员结构保存上一层caller的栈帧地址),这样函数返回、查看函数调用链都可以通过栈帧链表完成。这些都是通过编译器完成的,编译器通过生成对应的汇编代码,用栈的形式来维护、管理这些函数的变量、参数。
而堆空间这段内存,一般放在BSS段的后面。我们使用C库函数malloc/free申请的内存空间都是放在这段空间内。用户可以通过C标准库函数malloc/free进行内存的动态申请和释放。
而关于堆空间的管理,怎么说呢,管理就像小卖部和批发市场的关系。你烟瘾犯了,想买包烟,如果每次买包烟都到100公里外的批发市场,成本太高,开销太大,不划算。怎么办呢?小卖部的价值都体现出来了,小卖部会到批发市场批发几条烟,这样你每次买烟就不必到批发市场,出门左拐就是小卖部,方便快捷。但是如果某一次家里来客,你一下子想买10条烟,小卖部不够,怎么办呢?你告诉小卖部我想买10条烟,小卖部只有5条,这时候小卖部会到批发市场再进10条烟给你。
推荐阅读
- OC为何跌出语言榜前十
- dart这编程语言现在发展怎么样了,语法与Java,c#很相似,甚至更简洁
- 人民车市|新语言、新起点,捷达VS7 强势入局
- C语言 指针引用数组的地址问题
- 零基础入门学习啥语言好
- 营销型外贸网站用哪种建站程序和语言比较好呢主要是适合优化,可扩展兼容性,安全性,后期网站扩展升级
- 网页设计和嵌入式哪个发展好一点?
- 有哪些轻易就被识别的淘宝刷单评论语言
- C语言指数函数代码
- 我现在在学c语言,然后以后的工作目标是腾讯网易这些游戏公司,我是通信专业,请问我接下来再该学些啥呢