0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看威廉希尔官方网站 视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

干货 | 嵌入式C语言的内存管理

AGk5_ZLG_zhiyua 来源:YXQ 2019-07-23 14:32 次阅读

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

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

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

动态内存的原理

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

内存泄漏令开发者头痛的地方也正是这个原因,内存泄漏的问题往往无法在第一时间被发现!而对于不熟悉内存管理的开发者更是难以定位错误。

对于动态内存的操作,需要时刻记住:当一块申请的内存不再使用的时候,必须及时释放。一个malloc操作需要对应一个free操作。

4、内存对齐

在很多的场合下,分配的内存不仅要满足申请的大小,也需要进行对齐才能够使分配的空间能够被转换成除char之外其他的结构类型。系统对内存的分配一般会以int型变量的字节数进行对齐。AWorks提供的aw_mem_align接口可以使用户获取自定义对齐的内存空间。

类型对齐相关的知识请读者自行查找相关资料,这里不再展开细讲。

内存管理算法

接下来我们学习一下怎么去对堆空间的内存进行管理。这里我们主要介绍嵌入式中两种常用的内存管理算法。

1、链表法

链表法维护着两个链表,两个链表分别记录着已分配的使用内存段和未分配的空闲内存段。当申请一片内存的时候,从空闲内存段中找到合适的块分配给用户,同时链入使用内存段。而释放的时候则从已使用的内存段找到相应的表,然后释放到空闲内存段中以供下次分配。

现在我们以最先匹配算法为例介绍算法的细节。最先匹配算法是从空闲链表的表头出发,依次寻找空闲的内存,一旦找到足够大的连续区域则将其返回给用户。

还记得前面说的,管理内存区域需要额外的记录信息,链表法一般是在操作内存空间的时候申请额外的空间记录相应的信息。我们假定下图红色部分记录着使用的内存区,青色记录空闲的内存区,这里使用free link链表维护空闲内存段,used link维护使用的内存段:

程序运行一段时间之后,假设堆内的空间分布如下:

空闲区和使用区的信息都被两个表维护着。

现在用户需要申请一片大小为3k的内存,系统会从free link出发,先是找到2k的空闲区,由于2k的空间不够用,接下来再继续寻找,找到了4k的区域,发现4k的区域够大了,就会将4k的空间取走3k的空间并将其链入used link。

尽管后面3k的空间更加适合分配,但是最先匹配算法一旦找到足够大的空间便不会继续往下寻找。

当用户用完资源的时候,把申请的3k还回去,系统会从used link找到申请的内存,将链入free link以供下次分配,然后将空闲相邻的内存块合并成完整的一块:

现在考虑这样的一种情况:假设用户要申请5k的内存块,系统能够提供吗?并不能。

虽然空闲的内存块一共有9k(2k+4k+3k),但是9k的内存并不连续,因此无法分配给用户。这就是外部内存碎片——虽然整个空间的空闲内存足够大,但却因为零碎的内存块割裂了连续内存而无法分配出去。

其他的链表法还有最佳匹配算法,下次匹配算法等.有兴趣的读者可以自行查找相关资料。

2、位图法

使用位图法,系统的内存会被划分成固定的内存块。再用变量的其中一位指示其中的一块内存:

图中的一个方格代表一块固定大小的内存块,这里假定1k。用一个16位的变量指代16k的内存段。如果一个块是空闲的,则用0表示,如果是被使用的,则用1表示。

下图的第1,2个内存块和第7,8,9个内存块都被使用了,而相应的位都被置1说明被占用了。

相比链表法,位图法采用更少的额外空间记录内存堆的信息,而且由于申请与释放都是整块的,会产生更少的外部碎片。

但是假如用户只申请几个字节的内存,但是却分配了1k的内存块,则大量的空间不会被使用,这样导致的无法使用的内存我们称为内部内存碎片。

减少内部内存碎片的其中一个方法是合理地选择内存块的大小,固定尺寸较小的内存块导致的内存碎片会更小——当用户申请几字节的内存,比起固定1k的内存块,固定16字节的内存块产生更少的碎片。但是固定尺寸变小了也会导致需要更多的位记录内存的信息。

现在有很多优秀的位图算法——将内存分成不同的固定大小获取更快的分配速度和更少的内存碎片,有兴趣的读者可自行查找相关资料。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5082

    文章

    19114

    浏览量

    304888
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136722

原文标题:AWorks编程:嵌入式C语言的内存管理

文章出处:【微信号:ZLG_zhiyuan,微信公众号:ZLG致远电子】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    嵌入式 C 语言

    库函数支撑调用,分配的内存是电脑的内存,其处理器就是电脑的CPU;而在嵌入式环境中,会涉及到底层的硬件,而硬件本身是没有标准库可以调用的,因而就需要开发者使用C
    发表于 07-01 08:58

    标准C语言嵌入式C语言有哪些区别

    嵌入式系统是各行各业的具体应用相结合的产物。例如计算机威廉希尔官方网站 、半导体威廉希尔官方网站 、电子威廉希尔官方网站 。其更在乎效率和内存有效使用。嵌入式系统是一个威廉希尔官方网站 密集、资金密集、高度分散、不断创新的知识集成系统。C
    发表于 12-14 06:15

    如何使用嵌入式内存分配管理威廉希尔官方网站

    嵌入式---内存分配管理嵌入式内存一般都非常的小,最进在学习LWIP协议栈的移植,在正点原子的学习资料中找到了许多关于怎么移植协议栈的东西
    发表于 12-17 06:41

    ARM嵌入式系统C语言编程

    无操作系统支持的嵌入式系统软件,包括系统引导(BOOT) 、驱动程序、动态内存管理、IPO、通信以及应用软件等方面。本文详细介绍了嵌入式平台上用C
    发表于 11-07 15:55 165次下载

    嵌入式c语言编程(由浅入深)

    本内容详细介绍了嵌入式c语言编程的各项知识,包括嵌入式c语言编程,
    发表于 11-02 14:37 0次下载
    <b class='flag-5'>嵌入式</b><b class='flag-5'>c</b><b class='flag-5'>语言</b>编程(由浅入深)

    嵌入式外中断c语言代码

    嵌入式外中断c语言代码(arm嵌入式开发实例)-嵌入式外中断c
    发表于 07-30 11:29 4次下载
    <b class='flag-5'>嵌入式</b>外中断<b class='flag-5'>c</b><b class='flag-5'>语言</b>代码

    嵌入式C语言-文件操用

    嵌入式C语言-文件操用(嵌入式开发需要什么证书)-嵌入式C
    发表于 07-30 11:56 15次下载
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>语言</b>-文件操用

    标准c语言嵌入式,嵌入式C语言C语言的区别

    嵌入式C语言C语言的区别:最常用的系统编程语言C
    发表于 10-20 14:06 6次下载
    标准<b class='flag-5'>c</b><b class='flag-5'>语言</b>与<b class='flag-5'>嵌入式</b>,<b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>语言</b>与<b class='flag-5'>C</b><b class='flag-5'>语言</b>的区别

    嵌入式linux c语言,嵌入式LinuxC语言开发工具.pdf

    2 章 嵌入式Linux C 语言开发工具本章目标任何应用程序的开发都离不开编辑器、编译器及调试器,嵌入式Linux 的C
    发表于 11-01 17:38 12次下载
    <b class='flag-5'>嵌入式</b>linux <b class='flag-5'>c</b><b class='flag-5'>语言</b>,<b class='flag-5'>嵌入式</b>LinuxC<b class='flag-5'>语言</b>开发工具.pdf

    嵌入式 Linux 中的内存管理

    点击 嵌入式 Linux 中的内存管理
    发表于 11-02 10:36 12次下载
    <b class='flag-5'>嵌入式</b> Linux 中的<b class='flag-5'>内存</b><b class='flag-5'>管理</b>

    C语言嵌入式培训 嵌入式C语言程序设计基础

      学习嵌入式的基础语言C语言,因此先掌握C语言对于后续
    发表于 11-03 21:06 32次下载
    <b class='flag-5'>C</b><b class='flag-5'>语言</b><b class='flag-5'>嵌入式</b>培训  <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>语言</b>程序设计基础

    嵌入式C语言知识总结

    1 嵌入式C语言总结从语法上来说C语言并不复杂, 但编写优质可靠的嵌入式
    发表于 12-20 19:44 12次下载
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>语言</b>知识总结

    c语言嵌入式编程

    比较详尽的嵌入式C语言解答和分析
    发表于 03-10 14:53 162次下载

    嵌入式C语言的结构特点

    嵌入式开发中既有底层硬件的开发又涉及上层应用的开发,即涉及系统的硬件和软件,C语言既具有汇编语言操作底层的优势,又具有高级语言功能性强的特点
    的头像 发表于 11-24 16:16 677次阅读
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b><b class='flag-5'>语言</b>的结构特点

    嵌入式C语言高手炼成之内存操作篇

    嵌入式系统的编程中,常常要求在特定的内存单元读写内容,汇编有对应的MOV指令,而除C/C++以外的其它编程语言基本没有直接访问绝对地址的能
    的头像 发表于 12-11 17:20 510次阅读