对堆、栈的理解,对内存分配的理解

时间:2024-04-07 13:36:21

翻看了很多有关堆栈的文章,也跟朋友讨论了半天malloc、free的用法。很多像我一样的小白,刚开始都没有深入了解这些概念,因为根本用不到啊,刚开始入行时程序能不能跑都没谱呢,确实接触不到这些东西。但我现在入行时间差7天就三年了,这些东西渐渐出现我的视野中,研究开始入细。比如在cubemx、iar中设置的heap\stack的大小都是怎么定的?有时候程序越写越大,会有程序起不来的情况,是什么导致的?什么是内存分配?我定义的结构体是放在堆中还是栈中?他们是在单片机的哪个部分?

当你无法逃避问题的时候,最好的办法就是面对他,击败他。


一、内存是个啥?

内存到底是什么东西?人们口中所说的内存就是RAM。也就是计算机中的内存条,手机中的运行内存,单片机中的RAM。我们看cubemx对stm32f429IGt6的参数描述256KB:

对堆、栈的理解,对内存分配的理解

他说的RAM,但在文字描述时描述为SRAM,RAM和SRAM一样吗?

 

对堆、栈的理解,对内存分配的理解

《stm32f4xx中文参考手册》说:

对堆、栈的理解,对内存分配的理解

准确的说:RAM包括SRAM和DRAM还有SDRAM,他们又有什么区别呢?

RAM  
RAM(random access memory,随机存取存储器)。存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。这种存储器在断电时将丢失其存储内容,故主要用于存储短时间使用的程序。 按照存储信息的不同,随机存储器又分为静态随机存储器(Static RAM,SRAM)和动态随机存储器(Dynamic RAM,DRAM)。

SRAMS
RAM(Static RAM,静态随机存储器),不需要刷新电路,数据不会丢失,而且,一般不是行列地址复用的。但是他集成度比较低,不适合做容量大的内存,一般是用在处理器的缓存里面。像S3C2440的ARM9处理器里面就有4K的SRAM用来做CPU启动时用的。



DRAM
Dynamic RAM,动态随机存取存储器,每隔一段时间就要刷新一次数据,才能保存数据。而且是行列地址复用的,许多都有页模式。SDRAM是其中的一种。

SDRAM
SDRAM(Synchronous DRAM,同步动态随机存储器),即数据的读写需要时钟来同步。其存储单元不是按线性排列的,是分页的。
DRAM和SDRAM由于实现工艺问题,容量较SRAM大。但是读写速度不如SRAM。


一般的嵌入式产品里面的内存都是用的SDRAM。电脑的内存也是用的这种RAM,叫DDR SDRAM,其集成度非常高,因为是动态的,所以必须有刷新电路,每隔一段时间必须得刷新数据。

总结一下:就是说RAM是掉电不保存的内存体,涵盖SRAM、DRAM、SDRAM,他们都是掉电不保存的内存体。

其中,DRAM成本低,体量大,但是传输速度较慢,需要定时刷新,所以才叫动态内存。需要通电+刷新!

SRAM成本高,体量小,但是传输速度最快,而且不需要刷新,所以才叫静态内存。只需要通电!

SDRAM从名字看,好像是DRAM和SRAM集合体,但此S并非static,而是Synchronous-同步,所以根本上来说还是动态内存,需要刷新!

我们用的STM32中的内存是SRAM,就是无需刷新,掉电不保存的,但是速度很快。其中还有4K的备用区用的SRAM,用作RTC,由纽扣电池供电。
 


二、堆栈是个啥?

堆栈是什么东西?有什么区别?堆栈是一个模糊的说法,其实栈就是栈,堆就是堆,没有堆栈之说。栈和堆并不是一个内存,他们是一种内存使用的方式。我们通常用的是栈,就是后入先出方式,比如在函数中定义个uint8,那么就在SRAM中入栈一个uint8,在出函数时,再出栈。

其实我平时在工作时都不用malloc、free的,但是最近在学习原子的内存分配文章。而且我之前的师傅说过尽量少用malloc\free因为会造成很多奇奇怪怪的问题,我想就是文章中所说的,大量的malloc\free会使内存碎片化。

对堆、栈的理解,对内存分配的理解

堆、栈跟我们平时写代码有什么关系呢?就是我们平时定义的变量、结构体是放在具体哪个部分中呢?

内存分配方式有三种:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。 例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
栈内存 分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。
动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

图解我暂时没找到,下图是实时操作系统的内存分配方式图解,意思是一样的。我们可以看到最后空闲内存块变成了三个碎片。

对堆、栈的理解,对内存分配的理解

总结:

在程序中的全局变量、static变量放在静态存储区域,也就是程序编译后烧入单片机后所需的空间就已经在内存中分配好位空间了;

在函数内部的局部变量放在分配给栈的内存中,在程序运行到该函数的时候在栈中分配内存;

malloc、free是动态分配内存,从堆中寻找一块连续的指定大小的内存给一个指针malloc,用完了就把该堆中的内存free掉。

 

我们看实例分析:

对堆、栈的理解,对内存分配的理解

这是STM32F429IG的cubemx设置,它本身的SRAM共有0x40000大小,分配给堆的0x200,分配给栈的0x1000,剩下的空间是静态存储区域供全局变量和static存放的。


三、外部内存是个啥?

正点在内存管理篇章用的外部内存是啥?内存类型:SDRAM  型号:W9825G6KH  大小:32MB

该芯片用FMC接口与单片机相连,我们在使用中直接用FMC映射的地址即可

对堆、栈的理解,对内存分配的理解

具体使用请看原子的SDRAM章节,介绍的很详细。使用外部内存可以满足内存不够用的情况。


四、原子的内存管理如何实现的?

原子的内存管理并不是malloc、free,一句话都没有调用他们。说白了就是通过链表记录哪些扇区被标记使用了,空闲的扇区都有哪些,因为申请内存时需要从空闲扇区中申请连续的扇区,并返回地址给指针。释放的时候再把这些扇区号标记为空闲,指针指向NULL。


五、总结

由于在运行中不停的申请、释放内存容易造成内存碎片,少用malloc、free,如果非要用,那我建议在程序的初始化中可以申请内存,不要在运行中频繁申请释放内存。

水平有限,请大神指点一二