当前位置:首页 > 消费电子 > 消费电子
[导读]很多工程师都知道,C/C++语言与其他语言不同,它需要开发者自己管理内存资源,动态内存使用不当,容易造成段错误或者内存泄漏,因此内存管理至关重要。本文将以C语言为例介

很多工程师都知道,C/C++语言与其他语言不同,它需要开发者自己管理内存资源,动态内存使用不当,容易造成段错误或者内存泄漏,因此内存管理至关重要。本文将以C语言为例介绍动态内存管理的原理。

C/C++语言与其他语言不同,它需要开发者自己管理内存资源。对于动态内存的使用不当容易造成段错误或者内存泄漏。尤其是内存泄漏,内存泄漏往往是在程序运行一段时间才会被发现,使得开发人员无法第一时间定位错误。

而相比于个人计算机,嵌入式系统的内存资源更是稀缺。作为嵌入式C的开发人员,了解其内存管理的原理能使其更加正确地使用内存资源以及定位程序的bug。本文将以C语言为例介绍动态内存管理的原理。

动态内存的原理

1、栈空间与堆空间

在介绍内存管理之前,我们先解释一下栈空间与堆空间:栈空间是由编译器自动分配释放,对于AWorks等操作系统,在用户创建一个任务的时候可以由自己决定任务栈空间的大小。

栈空间里面一般存放着如下数据:在函数内的局部变量(不包括static定义的变量),在调用另一个函数时保存的通用寄存器信息等。

参考如下例程(为了便于理解,省略通用寄存器等信息):

 

 

在task执行s = calculate_sum(a,b);之前,task的栈内保存如下数据:

 

 

程序接下来执行calculate_sum函数,其栈向下增长。在返回task之前,其栈结构如下:

 

 

执行完calculate_sum之后,根据返回地址返回task之后,栈恢复调用之前的结构:

 

 

所以栈空间存储着代码块内的局部变量,动态地增减着内部的数据。这也就是为什么当接口调用结束后变量就不再“生存”的原因。

堆空间是由OS管理的一片区域,开发者可向OS动态申请一片区域用于操作数据。

堆空间在程序运行时一直有效,相当于定义了一个大型的全局数组。需要时向堆空间申请内存,使用完毕再还回去。这样可以使得开发者能够动态地控制空间的大小,而不需要在写代码的时候就考虑最糟的情况(定义一个数组必须在编译之前就确定其大小,使用过程中无法增加或减少,所以必须考虑最多需要的数据大小)。

堆空间由编译器决定,如果开发者想尝试实现一片动态内存,可向堆申请一片对齐的内存空间。

2、内存资源的申请与释放

我们这里以常用的内存操作接口——malloc与free为例,介绍操作动态内存的细节。

void* malloc(size)——申请一片大小为size字节的内存。

参考下图,灰色部分是已经被使用的内存,空白部分则是可以被申请使用的内存。在申请内存的时候,系统会首先判断有没有足够大的未被使用的区域,如果有,则将其分配给申请者,再将此区域标记为“已使用”;否则分配失败。

 

 

(为方便读图,从这里开始我们假定内存的地址从上往下增长)

void free(void *)——释放已申请的内存。与malloc相反,free的作用是把“已使用”的区域标记为“未使用”,那么释放的内存下一次就可以再分配出去复用。free释放的内存必须是malloc申请的内存。

由于需要对内存进行状态标记和位置记录(以便释放)。在申请/释放内存的时候需要额外的空间进行信息的记录。有的系统会将记录的信息集中管理,有的则是申请内存的时候额外地多申请一小片区域用于记录。

3、内存泄漏

对于动态申请的内存,使用完毕之后应该还给堆,才能在后续继续分配出去。而如果申请的内存如果没有还回去,就造成了内存泄漏。参考如下一段代码:

 

 

现在我们设flag=1,执行这个函数会发生什么?

首先ptr会指向申请的128字节的内存(图b),然后判断flag==1之后再申请256字节的内存(图c)。假设我们现在使用完毕将ptr释放:

现在我们释放了256字节的内存块了,但是我们开始的时候还申请过128字节的内存块,这128字节的内存块最终会怎样呢?由当时唯一指向这块内存的指针ptr后面指向了256字节的内存块,现在没有任何指针指向这块内存,因此这一块内存再也无法被释放,这时候我们就说内存泄漏了。

在程序最开始运行的一段时间内,系统是没有异常的。即使一小片内存不被释放也不会造成错误,因为内存堆还有足够的空间可以使用。但是如果运行的时间足够长,多次调用这个函数(参数flag==1)之后,堆空间会逐渐被泄漏的内存块占满,直到程序无法再从堆里申请到内存,程序才会报错。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭