历史上的今天
返回首页

历史上的今天

今天是:2025年04月01日(星期二)

正在发生

2019年04月01日 | STM32 内存分配详解

2019-04-01 来源:eefocus

1、KEIL 编译后数据


code

RO-data

RW-data

ZI-data

flash 实际存储数据

2、内存段


bss 段、data段、text段、堆(heap)和栈(stack)。


2.1、bss 段


bss 段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域;


bss 是英文Block Started by Symbol的简称;


bss 段属于静态内存分配。 


2.2、data 段


数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域;


数据段属于静态内存分配。 


2.3、text 段


代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域;


这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序);


在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。


2.4、堆(heap)


堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减;


当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);


当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。


2.5、栈(stack)


栈又称堆栈,是用户存放程序临时创建的局部变量;


也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量);


除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中;


由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场;


从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。 


2.6、一个程序本质上都是由 bss 段、data 段、text 段三个组成


在嵌入式系统的设计中也非常重要,牵涉到嵌入式系统运行时的内存大小分配,存储单元占用空间大小的问题。


在采用段式内存管理的架构中(比如intel的80x86系统),bss 段通常是指用来存放程序中未初始化的全局变量的一块内存区域。


一般在初始化时 bss 段部分将会清零,bss 段属于静态内存分配,即程序一开始就将其清零了。


比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。


text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载,而bss段不在可执行文件中,由系统初始化。


2.6、示例


两个小程序如下:


程序1:


int ar[30000];

void main()

{

    ......

}

程序2:


int ar[300000] = {1, 2, 3, 4, 5, 6 };

void main()

{

    ......

}

发现程序2编译之后所得的.exe文件比程序1的要大得多。


编译并使用了/FAs编译选项来查看了一下其各自的.asm。


程序1.asm中ar的定义如下:


_BSS SEGMENT

     ?ar@@3PAHA DD 0493e0H DUP (?)  ; ar

_BSS ENDS

而在程序2.asm中,ar被定义为:


_DATA SEGMENT

     ?ar@@3PAHA DD 01H  ; ar

                DD 02H

                DD 03H

                ORG $+1199988

_DATA ENDS

区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:


全局的未初始化变量存在于.bss段中,具体体现为一个占位符;


全局的已初始化变量存于.data段中;


而函数内的自动变量都在栈上分配空间;


.bss 是不占用.exe文件空间的,其内容由操作系统初始化(清零);


.data 却需要占用,其内容由程序初始化,因此造成了上述情况。


bss 段(未手动初始化的数据)并不给该段的数据分配空间,只是记录数据所需空间的大小;


bss 段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在数据段后面。


data 段(已手动初始化的数据)则为数据分配空间,数据保存在目标文件中;


data 段包含经过初始化的全局变量以及它们的值,当这个内存区进入程序的地址空间后全部清零。

 

包含 data 段和 bss 段的整个区段此时通常称为数据区。


3、内存管理


STM32 的存储器结构中 Flash,SRAM 寄存器和输入输出端口被组织在同一个 4GB 的线性地址空间内。


可访问的存储器空间被分成8个主要块,每个块为512MB。


FLASH存储下载的程序,SRAM是存储运行程序中的数据。


所以,只要不外扩存储器,写完的程序中的所有东西也就会出现在这两个存储器中。



3.1、STM32 中的堆栈


单片机是一种集成电路芯片,集成CPU、RAM、ROM、多种I/O口和中断系统、定时器/计数器等功能。CPU中包括了各种总线电路,计算电路,逻辑电路,还有各种寄存器。


Stm32 有通用寄存器 R0‐ R15 以及一些特殊功能寄存器,其中包括了堆栈指针寄存器。


当stm32正常运行程序的时候,来了一个中断,CPU就需要将寄存器中的值压栈到RAM里,然后将数据所在的地址存放在堆栈寄存器中。


等中断处理完成退出时,再将数据出栈到之前的寄存器中,这个在C语言里是自动完成的。


3.2、编程中的堆栈


在编程中很多时候会提到堆栈这个东西,准确的说这个就是RAM中的一个区域。


我们先来了解几个说明:


1) 程序中的所有内容最终只会出现在flash,ram里(不外扩);


2) 段的划分,是将类似数据种类存储在一个区域里,方便管理,但正如上面所说,不管什么段的数据,都是最终在flash和ram里面。


C 语言上分为栈、堆、bss、data、code段。


MDK 下分为:Code、RO-data、RW-data、ZI-data 这几个段;


Code是存储程序代码的;


RO-data是存储const常量和指令;


RW-data是存储初始化值不为0的全局变量;


ZI-data是存储未初始化的全局变量或初始化值为0的全局变量;


Flash=Code + RO Data + RW Data;


RAM= RW-data+ZI-data;


这个是 MDK 编译之后能够得到的每个段的大小,也就能得到占用相应的FLASH和RAM的大小,但是还有两个数据段也会占用RAM,但是是在程序运行的时候,才会占用,那就是堆和栈。


在stm32的启动文件.s文件里面,就有堆栈的设置,其实这个堆栈的内存占用就是在上面RAM分配给RW-data+ZI-data之后的地址开始分配的。


堆:


是编译器调用动态内存分配的内存区域;


栈:


是程序运行的时候局部变量的地方,所以局部变量用数组太大了都有可能造成栈溢出。


堆栈的大小在编译器编译之后是不知道的,只有运行的时候才知道,所以需要注意一点,就是别造成堆栈溢出了,会出现 hardfault 问题。


3.3、OS中的堆栈及其内存管理


两种获得内存情况:


1)用庞大的全局变量数组来圈住一块内存,然后将这个内存拿来进行内存管理和分配。


这种情况下,堆栈占用的内存就是上面说的;


如果没有初始化数组,或者数组的初始化值为0,堆栈就是占用的RAM的ZI-data部分;


如果数组初始化值不为0,堆栈就占用的RAM的RW-data部分。


这种方式的好处是容易从逻辑上知道数据的来由和去向。


2)就是把编译器没有用掉的RAM部分拿来做内存分配,也就是除掉RW-data+ZI-data+编译器堆+编译器栈后剩下的RAM内存中的一部分或者全部进行内存管理和分配。


这样的情况下就只需要知道内存剩下部分的首地址和内存的尾地址,然后要用多少内存,就用首地址开始挖,做一个链表,把内存获取和释放相关信息链接起来,就能及时的对内存进行管理了。


内存管理的算法多种多样,不详说,这样的情况下:OS的内存分配和自身局部变量或者全局变量不冲突,之前我就在这上面纠结了很久,以为函数里面的变量也是从系统的动态内存中得来的。


这种方式感觉更加能够明白自己地址的开始和结束。

推荐阅读

史海拾趣

Eclipse Magnetics公司的发展小趣事

由于篇幅限制,无法在此处直接提供5个完整的、每篇至少500字的Eclipse Magnetics公司电子行业发展的相关故事。不过,我可以概括地描述几个可能的故事线索,这些线索可以基于Eclipse Magnetics公司的历史、技术发展和市场应用来构建。

  1. 品牌初创与磁铁技术的突破

在1930年代,Eclipse Magnetics的名字首次出现,标志着这个品牌的诞生。随着技术的不断发展,公司在1940年代成为独立公司,并开始专注于磁铁技术的研发。到了1950年代,Eclipse Magnetics在技术上取得了重大突破,他们将磁铁涂上红色,并设计了与公司颜色相匹配的马蹄形标志,这一设计不仅提升了品牌形象,也成为了国际通用标记。这一时期的Eclipse Magnetics,以其独特的技术和产品,开始在电子行业中崭露头角。

  1. 航空航天领域的应用与拓展

随着航空航天技术的不断发展,Eclipse Magnetics看到了磁铁技术在该领域的巨大潜力。公司开始投入大量资源,研发适用于航空航天领域的磁性解决方案。通过不断的技术创新和产品优化,Eclipse Magnetics成功地为航空航天领域提供了高性能、高可靠性的磁铁产品,并在这一领域树立了良好的口碑。

  1. 与制药工业的深入合作

除了航空航天领域,Eclipse Magnetics还与制药工业建立了深入的合作关系。在制药过程中,磁铁技术可以用于磁选机,有效地去除原料中的杂质,提高药品的纯度。Eclipse Magnetics根据制药工业的特殊需求,定制了多款磁选机产品,并提供了全面的技术支持和售后服务。通过与制药工业的深入合作,Eclipse Magnetics不仅拓展了市场,也提升了自身的技术实力。

  1. 在汽车制造行业的应用

随着汽车制造业的快速发展,Eclipse Magnetics也看到了磁铁技术在该领域的广阔前景。公司针对汽车制造中的各个环节,研发了多款适用于不同场景的磁性解决方案。例如,在齿轮箱轴制造过程中,Eclipse Magnetics的磁性过滤器可以保持冷却液的清洁,提高生产效率和产品质量。这些解决方案不仅满足了汽车制造业的需求,也进一步巩固了Eclipse Magnetics在电子行业中的地位。

  1. 创新研发与可持续发展

作为一家专注于磁性技术的公司,Eclipse Magnetics始终将创新作为发展的核心动力。公司不断投入研发资源,推动磁铁技术的不断进步。同时,Eclipse Magnetics也关注可持续发展问题,致力于研发环保、高效的磁性产品。通过创新研发和可持续发展战略的实施,Eclipse Magnetics在电子行业中保持了领先地位,并为未来的发展奠定了坚实的基础。

请注意,以上内容仅为故事线索的概括描述,具体的故事细节和数据需要根据Eclipse Magnetics公司的实际情况进行补充和完善。

Everett Charles Technologies (ECT)公司的发展小趣事

2001年,Everett Charles Technologies (Shenzhen) Limited(ECT深圳)正式成立,成为Dover集团在中国的全资子公司。ECT深圳的成立,不仅为ECT在中国市场的业务拓展提供了有力支持,也为公司进一步拓展亚洲市场奠定了基础。多年来,ECT深圳凭借卓越的产品质量和服务水平,赢得了众多客户的信赖和支持,成为ECT在亚洲地区的重要生产基地。

大毅科技公司的发展小趣事

随着业务的不断增长,大毅科技意识到需要扩大生产规模以满足市场需求。于是,公司开始在大陆地区寻找合适的生产基地,最终在东莞、清溪、苏州等地设立了生产基地。这一举措不仅降低了生产成本,还提高了生产效率,使大毅科技能够更好地服务全球客户。同时,这也体现了大毅科技对全球市场的战略眼光和布局。

Easy Braid公司的发展小趣事

Easy Braid公司,从一家名不见经传的小型电子制造商起家,其发展的故事始于一次技术创新。在公司成立初期,面对市场上繁多的线缆管理方案,Easy Braid的创始人意识到传统方法的局限性,于是带领团队研发了一种新型的线缆编织技术——Easy Braid技术。这种技术不仅提高了线缆的耐用性和美观度,还大大简化了安装过程。随着这一技术的推出,Easy Braid开始逐渐在电子行业中崭露头角。

电连(ECT)公司的发展小趣事

随着汽车智能化的发展,ECT看到了车载连接器市场的巨大潜力。从2013年开始,公司开始布局车载连接器领域,并成功开发出多款适用于不同车型和场景的车载连接器产品。这一拓展不仅为ECT带来了新的增长点,也进一步巩固了公司在电子连接器行业的领先地位。

Cystech公司的发展小趣事

C-TECH Co., Ltd非常重视产品质量管理。公司自成立之初就引入了ISO 9001质量管理体系,并严格按照体系要求进行生产和管理。此外,公司还不断投入资源提升产品质量检测水平,确保每一款产品都能满足客户的需求和期望。正是凭借对品质的严格把控和持续改进,C-TECH Co., Ltd赢得了客户的广泛信任和好评。

问答坊 | AI 解惑

关于视频系统处理器选择的建议

关于视频系统处理器选择的建议基于ARM核心的Freescale的i.MX系列芯片是视频应用的佼佼者。 比如i.MX27和i.MX31 i.MX27嵌入式开发板是高清视频输入输出的首选,i.mx27芯片提供了更高的灵活性和更强大的多媒体处理能力,成为IP视频和语音(V2IP)、移 ...…

查看全部问答>

关于7行5列LED键盘指示灯的编程,请高手解惑!十万火急!万分感谢!

7行5列的LED键盘指示灯,键按下时相应的LED指示灯也会亮! 灯亮的原则:列为高电平,行为低电平。 我想问的是,如果我知道了第0行第0列的键按下了,想要第0行第0列的灯亮,那么是不是应该让列所在的存储器第0位置1,其余列置0!即将0x01输入到相 ...…

查看全部问答>

自制超级流水灯演示板

单片机的用途非常广阔,各种智能控制的产品中都少不了它的身影,前景看好,因此引起了一阵阵学习单片机的热潮。   相信很多初学单片机的朋友都是从做流水灯开始的,因为流水灯的电路较为简单。看着按照自己的设想做成的流水灯变幻着不同的花样, ...…

查看全部问答>

ARM板上如何增加显卡芯片

如题, 望版主推荐 一直以来,因ARM开发板每次换屏的时候都要重新生成NK,有没人做过在板子上驱动一个显卡IC来驱动LCD? 如果有,IC型号大家了解的有哪些? 如果增加了这个显卡IC,那么原来的Display驱动还要不要? 大家一起讨论讨论,突然想 ...…

查看全部问答>

谁能详细讲讲 uboot smdk2410.h 里面配置信息的含义?

谢谢! 我是初学者,不明白里面都在配置些什么,不明白哪些是最重要的。…

查看全部问答>

关于vs2005开发windows ce 5程序部署到机器的问题

1:首先非常感谢您的帮助,同时我找遍了google和baidu,没有找到,或许是关键字搜索的不好。所以来此提问。 2:问题描述如下    机器是广州市微嵌计算机科技的Arm9 的硬件系统,采用的是windows ce 5.0。该设备有一个特点是会将hwDir目 ...…

查看全部问答>

如何使程序某个功能运行时不响应其它操作

小弟要实现如下功能: 当我点击打印操作时,程序弹出一个对话框,显示正在打印,在打印的过程中,必须使程序无法响应用户的其它任何操作。当打印结束时,显示打印成功或打印失败,然后才让程序可以继续响应用户其它操作。 请问这个如何解决哈? …

查看全部问答>

讨论: 用fread, fwrite存取结构数据安全吗?

同样的软件,平时都用的好好的,但有半天fread出来的数据都不对。于是才产生这个疑问.…

查看全部问答>

压力传感器在汽车空调系统中是如何应用的?

在汽车空调系统中,压力传感器都应用在那部分,又是给那里提供数据,这些数据的作用。请各位大侠指点指点。谢谢!…

查看全部问答>