历史上的今天
返回首页

历史上的今天

今天是:2025年02月05日(星期三)

正在发生

2021年02月05日 | STM32 内存分配详解

2021-02-05 来源: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的内存分配和自身局部变量或者全局变量不冲突,之前我就在这上面纠结了很久,以为函数里面的变量也是从系统的动态内存中得来的。

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

 

refer:

https://www.cnblogs.com/yanghong-hnu/p/4705755.html
http://blog.sina.com.cn/s/blog_89f2fa3d0102vl9q.html
https://blog.csdn.net/shenghuaday/article/details/78877949


推荐阅读

史海拾趣

Golledge Electronics公司的发展小趣事

Golledge Electronics公司的发展故事

故事一:石英晶体振荡器的创新起点

Golledge Electronics公司的起源可以追溯到对石英晶体振荡器技术的深入研究和创新。公司最初成立于英国水晶产区的中心,依托当地丰富的水晶资源,Golledge迅速成为石英晶体振荡器领域的佼佼者。公司创始人敏锐地意识到石英晶体的压电特性在电子系统中的重要应用价值,于是投入大量资源进行研发。通过不断优化晶体制造工艺和温度补偿技术,Golledge成功推出了高精度、高稳定性的石英晶体振荡器,为无线电通信、卫星通信等领域提供了关键技术支持。这一创新不仅奠定了Golledge在电子行业的基础,也为其后续发展铺平了道路。

故事二:微机电系统(MEMS)技术的突破

随着电子产品的不断小型化和便携化,Golledge Electronics公司紧跟时代步伐,将研发重点转向微机电系统(MEMS)技术。MEMS谐振器以其紧凑的尺寸和稳健的性能,成为便携式设备和可穿戴设备中的理想选择。Golledge通过自主研发和合作创新,成功将MEMS技术应用于频率控制产品中,推出了多款高性能、低功耗的MEMS谐振器。这些产品不仅满足了市场对小型化、轻量化的需求,还进一步提升了电子系统的整体性能和可靠性。Golledge在MEMS技术领域的突破,为其在电子行业中的领先地位增添了新的动力。

故事三:新材料应用的探索

为了不断提升产品的性能和质量,Golledge Electronics公司始终致力于新材料的研发和应用。公司研发团队通过深入研究石英晶体的物理特性和化学性质,成功开发出了一系列具有独特性能的石英晶体材料。这些新材料不仅具有更高的稳定性和频率精度,还能够在极端环境下保持优异的性能表现。Golledge将这些新材料应用于频率控制产品中,显著提升了产品的竞争力和市场占有率。同时,公司还积极探索其他新型材料的应用潜力,为未来的技术创新储备了丰富的资源。

故事四:机器学习集成的创新实践

随着人工智能技术的快速发展,Golledge Electronics公司敏锐地捕捉到这一趋势,并积极探索机器学习在频率控制领域的应用。公司研发团队通过集成机器学习算法,使频率控制系统能够动态地适应和优化频率设置。这一创新实践不仅确保了频率控制系统的持续准确性,还为其赋予了自我学习和自我优化的能力。Golledge的这一创新成果,不仅提升了产品的智能化水平,也为电子行业的未来发展提供了新的思路和方向。

故事五:超微型SMD晶体的商用化

为了满足市场对更小、更轻、更高效的电子产品的需求,Golledge Electronics公司推出了超微型1610mm封装SMD晶体,并成功实现商用化。这款晶体以其极小的尺寸和优异的性能,迅速赢得了市场的青睐。Golledge通过不断优化生产工艺和质量控制体系,确保了超微型SMD晶体的稳定供应和高质量表现。这款产品的成功商用,不仅进一步巩固了Golledge在电子行业中的地位,也为其在小型化、便携化电子产品领域的发展开辟了新的市场空间。

Feller US公司的发展小趣事

菲斯克(FSR.US)作为一家新兴的电动汽车制造商,自创立之初便面临着巨大的挑战。资金紧张是公司面临的首要问题,为了维持运营和推进研发,公司不得不频繁地寻求融资。在一次次的融资尝试中,菲斯克展现了其坚定的决心和创新的理念,虽然过程充满艰辛,但公司最终通过不断努力,成功获得了一笔重要的投资,为公司的发展奠定了坚实的基础。

HBH-Microwave公司的发展小趣事

在电子行业中,客户需求往往具有多样性和特殊性。HBH-Microwave深知这一点,因此始终将提供定制化解决方案作为公司的核心竞争力之一。公司拥有一支专业的研发团队和完善的生产体系,能够根据客户的具体需求,快速设计出符合要求的微波组件和子系统。这种灵活性和高效性使得HBH在众多竞争对手中脱颖而出,赢得了大量客户的信赖和好评。

bb-smartworx公司的发展小趣事

为了加速全球化进程,HBH-Microwave积极寻求与国际知名企业的合作。通过技术交流和联合研发,HBH与多家跨国公司建立了长期稳定的合作关系。这些合作不仅为公司带来了先进的技术和管理经验,也帮助HBH的产品成功打入国际市场,实现了销售额的快速增长。同时,HBH还通过参加国际展会和研讨会,不断提升品牌知名度和行业影响力。

GaN Systems公司的发展小趣事

随着市场的不断拓展和技术的不断进步,GAIA盖亚电源持续加大研发投入,致力于技术创新和产品升级。公司拥有一支由超过300名工程师组成的研发团队,他们紧密关注行业动态,积极应对新技术和市场趋势。每年,GAIA盖亚电源都会推出数百种新产品,以满足不同客户的需求。这些新产品不仅涵盖了更广泛的电压范围和输出功率,还集成了最新的滤波、网络调节等先进技术,进一步提升了产品的性能和可靠性。

Display Elektronik GmbH公司的发展小趣事

Display Elektronik GmbH始终将产品质量放在首位。公司建立了严格的质量控制体系,从原材料采购到生产流程,再到成品检测,每一个环节都严格把关。这种对品质的坚持让Display Elektronik GmbH的产品在市场上赢得了良好的口碑,也为其赢得了众多知名客户的信赖。

问答坊 | AI 解惑

一种改进的电压跟随PFCCukAC/DC变换器

一种改进的电压跟随PFCCukAC/DC变换器 随着半导体器件的发展,电力电子装置的大量应用,导致大量谐波电流涌入电网,污染电网,这一问题已引起了各国的重视。为了限制总的谐波含量(THD)以提高功率因数,制定了许多标准,如IEC1000?3?2。近年来,如 ...…

查看全部问答>

求助:FFT-v2.1.1的介绍

本帖最后由 paulhyde 于 2014-9-15 09:50 编辑 哪位高手手头上有altera公司的FFT-v2.1.1 ipcore的介绍,麻烦发给我一份,不胜感激。 邮箱:hutiao-001@163.com  …

查看全部问答>

截图软件

找到一个很好的截图软件 分享一下…

查看全部问答>

eboot编译出错!!

在移植2440的usb下载nk功能到2410的eboot中时: s3c2410a_usbd.c文件中:三个函数定义和实现 BOOL UbootReadData (DWORD cbData, LPBYTE pbData); BOOL InitUSB (); void Isr_Init(); main.c文件中: // For USB Download function. extern ...…

查看全部问答>

关于MB90092 子屏显示的问题

我现在想用富士通的视频叠加MB90092芯片子屏显示功能,主屏可以正常显示。 子屏显示的字符为一段乱码,代码如下: void  MB90092_DisChar (UCHAR x,UCHAR y,int addr,UCHAR mul,UCHAR bc,UCHAR cc,UCHAR ff) {       ...…

查看全部问答>

小巧的LPC1114做图象开发板

    LPC1114到了,相机不在身边,拍不了照。呵呵!     前面已经我为他设计了一个舞台,该搭建了,让他在上面尽情的发挥。 [ 本帖最后由 zhdphao 于 2010-7-31 17:38 编辑 ]…

查看全部问答>

关于c8051F330单片机内部温度传感器的问题

是不是所有c8051f系列单片机(内部自带温度传感器),ADC在左对齐,单端方式下产生的代码与输入电压的关系都是这个方程式:CODE=Vin*(Gain/Vref)*2^16。还有输出电压与温度的关系式怎么有两个,Vtemp=2.5mV/C*Temp+0.603V和Vtemp=2.86mV/C*Temp+0. ...…

查看全部问答>

【TI原创】基于LM3S8962的网络收音机(五) --- PC端发送程序

为了配合LM3S8962+VS1053的调试,从网上下载并修改了一个发送文件的程序,用来完成:   1.  网络下载存储播放; 2.  网络实时播放   为进一步实现网络收音机的功能打下结实的基础。   代码功能简单,如下所示: # ...…

查看全部问答>