侵权投诉
订阅
纠错
加入自媒体

AWorks编程:嵌入式C语言的内存管理

2019-07-18 14:38
ZLG致远电子
关注

很多工程师都知道,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)之后,堆空间会逐渐被泄漏的内存块占满,直到程序无法再从堆里申请到内存,程序才会报错。

1  2  下一页>  
声明: 本文由入驻维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。

发表评论

0条评论,0人参与

请输入评论内容...

请输入评论/评论长度6~500个字

您提交的评论过于频繁,请输入验证码继续

暂无评论

暂无评论

文章纠错
x
*文字标题:
*纠错内容:
联系邮箱:
*验 证 码:

粤公网安备 44030502002758号