首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

堆 栈 重映射及内存分配理解

堆 栈 重映射及内存分配理解

所谓的理解硬件就是说,理解这个硬件是怎么组织这么多资源的,这些资源又是怎么由cpu、由编程进行控制的。
比如说,s3c2410中有AD转换器,有GPIO(通用IO口),还有nandflash控制器,这些东西都有一些寄存器来控制,这些寄存器都有一个地址,那么这些地址是什么意思?(也即是在内存中的位置,每个处理器都有其寻址的范围,我们把这个范围从0开始编号,一般都是按字节编址的,寄存器的地址就是在这个内存中的位置)
又怎么通过寄存器来控制这些外围设备的运转?(这个就是硬件的设计的功能了,例如手机开关按键按下就可控制手机的亮灭。向相应的寄存器中写入对应的数据就可实现相应的功能)
还有,norflash内部的每一个单元在这个芯片的内存中都有一个相应的地址单元,那么这些地址与刚刚说的寄存器地址又有什么关系?(可以说是一样的,不同之处是放入上面寄存器内的数据是控制相应外设的功能的,而norflash内的是用于存储数据的)
再有,使用ADS进对ARM9行编程时都需要使用到一个初始化的汇编文件,这个文件究竟有什么用?(指的是启动代码吧)
他里面的代码是什么意思?(为能顺利的执行我们用高级语言写的程序做准备的,例如硬件初始化,堆栈的分配等)
不要这个可以吗?(如果你的应用程序是使用汇编编写的就不需要这些)
诸如此类都是对硬件的理解,理解了这些东西就对硬件有很深的理解了,这对以后更深一步的学习将有很大的帮助。


每个设计的确都有它的现实考虑,编程语言是很实在的东西,往往外貌冷冰冰但其为什么是这样有充足原因。
1.内置数组,为什么不设置下标检测?如果检测下标,定然就会在每次访问下标时,做是否越界的检验,这就带来了运行时开销。如果你的算法非常好,定然不需要检测下标,则语言假定一定要在每次访问下标时都判断,就会影响效率并失去选择的机会。如果设置N个选项,可以用来关闭或打开是否检测下标,那不应该是一种语言应该干的,各有各的侧重点。

2.C语言传数组参数为什么默认是转换成指针类型?以C语言产生那个年代的硬件条件,复制数组很奢侈,尤其函数被调用往往很频繁,算法要尽量往不复制的情况下设计,如果实在必要,非要复制,你也可以手动memcpy嘛!总之它不是默认项。C++给了用户另一种选项,即通过加上引用,而使得能够真正传整个数组。


3.for语句为什么有的灵活有的严格?像在Ada中的语法,便是禁止循环变量被改变,且不能设置步长值,要想达到这两个目的,便只能用其他变量再过渡,这样做是为了高度的安全。反之,C语言的for则非常灵活,也没有Ada那么多的限制,但这种灵活并不能保证用户用其写出错误逻辑的代码;VB的自由度则介于二者之间。不能因为这些语言的设计不同,而指责其中某一种语言为何不对某一语法特性做必要的限制,它真的必要吗?个案好说,但综合全局,很难评估。

存储器映射与重映射

存储器映射是指把芯片中或芯片外的FLASH,RAM,外设等进行统一编址。即用地址来表示对象。这个地址绝大多数是由厂家规定好的,用户只能用而不能改。用户只能在挂外部RAM或FLASH的情况下可进行自定义。

存储器映射就是对各种存储器的大小和地址分布的规划。存储器重映射就是为了快速响应中断或者快速完成某个任务,将同一地址段映射到不同速度的两个存储块,对低速存储块的访问将被重映射为对高速存储块的访问。
为什么需要存储器重映射
目前很多嵌入式系统中的Flash分为Code Flash和Data Flash。Code Flash存放可以运行的程序代码,Data Flash存放应用数据。Code Flash通常被映射到0地址,系统上电复位后就从0地址开始执行。通常中断向量表就位于0地址的起始位置,系统上电复位后执行的第一条指令就是复位中断的跳转指令。
由于中断向量表位于CodeFlash中,Code Flash的读取速度比RAM慢,为了快速响应中断,就将RAM重映射到0地址,然后将中断向量表复制到RAM的起始位置。再发生中断时,访问Code Flash中的中断向量表,将被重映射为访问RAM中的中断向量表。
Boot Block是芯片设计厂商在LPC2000系列ARM内部固化的一段代码,用户无法对其进行修改或者删除。为了增加用户代码的可移植性,所以最好把Boot Block的代码固定的某个地址上。于是芯片厂家将Boot Block的地址重映射到片内存储器空间的最高端,即接近2Gb的地方,这样无论片内存储器的大小如何,都不会影响Boot Block的地址。



栈和堆的区别
栈是由编译器在需要时分配的,不需要时自动清除的变量存储区。里面的变量通常是局部变量、函数参数等。堆是由malloc()函数(C++语言为new运算符)分配的内存块,内存释放由程序员手动控制,在C语言为free函数完成(C++中为delete)。栈和堆的主要区别有以下几点:
(1)管理方式不同。
栈编译器自动管理,无需程序员手工控制;而堆空间的申请释放工作由程序员控制,容易产生内存泄漏。(设计多任务操作系统时还是需要自己为任务设计栈)
(2)空间大小不同。
栈是向低地址扩展的数据结构,是一块连续的内存区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,当申请的空间超过栈的剩余空间时,将提示溢出。因此,用户能从栈获得的空间较小。
堆是向高地址扩展的数据结构,是不连续的内存区域。因为系统是用链表来存储空闲内存地址的,且链表的遍历方向是由低地址向高地址。由此可见,堆获得的空间较灵活,也较大。栈中元素都是一一对应的,不会存在一个内存块从栈中间弹出的情况。
(3)是否产生碎片。
对于堆来讲,频繁的malloc/free(new/delete)势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低(虽然程序在退出后操作系统会对内存进行回收管理)。对于栈来讲,则不会存在这个问题。
(4)增长方向不同。
堆的增长方向是向上的,即向着内存地址增加的方向;栈的增长方向是向下的,即向着内存地址减小的方向。(不同的处理器可能不同)
(5)分配方式不同。
堆都是程序中由malloc()函数动态申请分配并由free()函数释放的;栈的分配和释放是由编译器完成的,栈的动态分配由alloca()函数完成,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行申请和释放的,无需手工实现。
(6)分配效率不同。
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行。堆则是C函数库提供的,它的机制很复杂,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大的空间,如果没有足够大的空间(可能是由于内存碎片太多),就有需要操作系统来重新整理内存空间,这样就有机会分到足够大小的内存,然后返回。显然,堆的效率比栈要低得多。
内存分配方式
内存分配方式有三种:
[1]从静态存储区域分配。该内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
[2]在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
[3]从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收它,否则运行的程序会出现内存泄漏,频繁地分配和释放不同大小的堆空间将会产生堆内碎块。
一个由C/C++编译的程序占用的内存分为以下几个部分:
1、栈区(stack)
由编译器自动分配释放,存放为运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

2、堆区(heap)
一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。

3、全局区(静态区)(static)存放全局变量、静态数据、常量。程序结束后由系统释放
4、文字常量区常量字符串就是放在这里的。程序结束后由系统释放。
5、程序代码区存放函数体(类成员函数和全局函数)的二进制代码。
返回列表