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

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

3天内不再提示

Keil C的应用动态存储管理的原理和实现方法分析

牵手一起梦 来源:单片机与嵌入式系统应用 作者:丁明亮,熊真春 2020-10-04 14:00 次阅读

Keil C是常用的嵌入式系统编程工具,它通过init_mempool、mallloe、free等函数,提供了动态存储管理等功能。本文通过对init_mempool、mallloe和free这3个KeilC库函数源代码的分析,揭示其实现的原理和方法,并对其中的不足作了改进,以使Keil C编程人员更好地应用动态存储管理。

1 相关数据结构、变量及说明

在Keil C安装目录下的\c5l\lib目录下,有实现init_mempool、mallloe和free这3个函数的C源文件init_mere.c、malloc.e和free.c。下面针对keil C7.5A版,将其中与动态存储管理相关的数据结构介绍如下:

Keil C的应用动态存储管理的原理和实现方法分析

该结构的next指向堆中的下一空闲内存块,len表示该空闲块除去该块首部的struct__mem__结构所占的字节数后,该块实际可用的字节数。由于next是一个指向XDATA区的指针,故在Keil C中应用程序所定义的堆空间应在XDATA段中定义。

在Keil C中,堆中的所有空闲内存块是用一个单链表来管理的,struct_mere_即为该链表结点的结构,后面定义的宏AVAIL为该链表的首结点,为叙述方便,以下将该链表称为AVAIL链表。

#define AVAIL(__meM_avaiL_[O])

全局数组__meM_ avail_实际也是struct__mem__类型,__mem_avail__[O]的next指向堆中首块空闲块。如果堆中已无空闲内存块,则__mem_avail__[0]的next为NULL(0值)。为使程序代码简洁,定义了宏AVAIL来代替__mem_avail__[O]。

2 init_mempool函数剖析

函数int_mempool(void_MALLOC_MEM_*pool,unsigned int size)失败时将返回0,成功则返回一1,参数pool指向应用程序定义的堆空间,参数size为堆空间的字节数。如果应用程序提供的堆空间太小(size的值太小),将失去实际意义,故函数将返回0表示失败。当size参数足够大,则会初始化AVAIL(即_mem_avail__[O]),使其next域指向pool参数所指向的堆空间,len域为pool参数所指向的堆空间的总字节数size。其在KeilC 7.5A库中init_mem.C的源代码如下:

在成功执行init_mempool函数后,将得到如图1所示的一个数据结构。另外,链首结点AVAIL的len域记录了整个堆的字节数。链首AVAIL结点的next域指向的是首块空闲块,当经过多次的malloe函数而堆中投有空闲内存块时,AVAIL结点的next域将为NULL值。

很明显,从上面的if(pool==NULL){pool=1;size--;)这部分源代码来看,如果应用程序中pool参数为空指针(pool为0)时,显然不能直接将AVAIL,的next域的值赋为空指针的(即赋为O)。将pool的值改为1,再将size的值减l,这样,init_mempool函数会在XDATA区中,从地址l开始,取size一1个字节作为堆来使用。如果源程序有定义在XDATA区的变量,则这些变量所占的存储单元也可能会被当成堆空间的一部分,这无疑是有潜在风险的。

部分程序员在调用init_mempool函数时,习惯将pool参数设为一个形如0xAAAA数字表示的绝对地址,如果不加特别防范,也是不妥的,因为Keil C可能会在此方式指定的堆空间中分配临时变量。好的习惯是定义一个字节数组作为堆空间,再将数组名作为pool参数调用init_mempool函数。

在Keil C的联机文档中,指明了init_mempool在应用程序中只能被调用一次,那么,如果多次调用该函数又会有什么后果呢?从该函数的源代码来分析,多次调用init_mempoo1函数,会导致重新初始化首结点AVAIL的next域和len域的值,将使AVAIL链表中的原有管理信息丢失,从而导致一些很难诊断的问题。

对此问题,可采用如下保护措施。当发现AVAIL链表中已有管理信息时,则返回失败标志,函数直接返回。具体的方法是检查AVAIL结点的len域,由于其被初始化为零,如果发现其值非零,则表明init_mempool函数已被成功调用过,此时函数直接返回。

3 malloc函数分析

malloc函数的原形是void *malloc(unsigned intsize),size参数为需动态申请的内存块的字节数。

malloc函数的算法是查找AVAIL链表中各结点next指针所指向的空闲内存块。如果某块的空闲字节数≥size参数,则停止查找,并从该块进行内存分配,返回一个指向所分配内存块的指针给应用程序。如果没有找到符合要求的空闲内存块,则返回空指针给应用程序。

需要注意的是,AVAIL链表中除首结点AVAIL外,其余各节点位于堆中各空闲内存块开始处的一个struct__mem__结构中,其len域为该空闲块总字节数减去sizeof(stiuct__mem)后的值,即该块实际空闲的字节数;next域指向堆中下一空闲内存块。

设链表节点p指向所找到的空闲内存块,如果在p空闲块分配size个字节后,剩余的字节数不多,则将p块从AVAIL链表中删除,然后返回一个指向p块偏移sizeof(struct__mem)处的指针。如果在p空闲块分配size个字节后,该块仍剩余较多的字节数,则需对该块进行分割,将多出的这一部分保留在AVAIL链表中。(以下部分有省略,全文请见本刊网站——编者注)

4 free函数分析及改进

free函数的原形是void free(void xdata *memp),参数memp指向所要释放的内存块。

在AVAIL链表中,各结点是按其所指空闲内存块开始地址的大小按升序排列的。free函数的算法是在AVAIL链表中查一个节点p(其前驱为q),当p节点所指空问内存块的地址大于参数memp所指内存块的起始地址时,则将memp块插入到该节点之前,如没有找到这样的节点,则memp块插到链尾。在插入memp块时,还将检查在memp块的前后是否存在地址相邻的空闲内存块,如果有,则将memp块与相邻块合并。

值得探讨的是最后一段将memp块与前一块(q块)合并的这部分代码。如果在执行此部分代码之前,q指向首结点AVAIL,而此时欲将q块与memp块合并,显然是不合理的。实际上,此时应当将q的next指针的值设为memp块的开始地址p0。由于KeilC7.5A中,free库函数的源程序中没有考虑这种特殊情况,因此可能会引发严重后果。

由源代码分析可知,q指向首结点AVAIL,而此时如果满足。memp块与q块合并的判定条件,执行q>1en+=p0一>Len+HL,EN和q一>next=pO一>next后,不但不能回收内存,反而导致memp块丢失;同时,AVAIL的len域的值也不正确。如果此时pO一>next又为NULL,则会导致整个堆内存的丢失。

笔者特在Keil C7.5 A版中设计了一个示例(见本刊网站),用于引发该错误。要防止这种错误,只需将if((((char_MALLOC_MEM_*)q)+q一>len+HLEN)==pO)判定语句改为if((q!=&AVAIL)&&(((char_MALLOC_MEM_*)q)+q一>len+HLEN)==p0)即可。有兴趣的可通过电子邮件与笔者联系(cqdoml@sina.com)。

责任编辑:gt

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

    关注

    5068

    文章

    19019

    浏览量

    303294
  • 编程
    +关注

    关注

    88

    文章

    3592

    浏览量

    93596
  • 函数
    +关注

    关注

    3

    文章

    4306

    浏览量

    62431
收藏 人收藏

    评论

    相关推荐

    Keil C动态内存管理机制分析及改进,不看肯定后悔

    Keil C动态内存管理机制分析及改进,不看肯定后悔
    发表于 04-25 08:48

    有什么方法可以实现逻辑分析仪的实时存储吗?

    有什么方法可以实现逻辑分析仪的实时存储吗?
    发表于 05-06 07:39

    怎样去实现嵌入式裸机内存动态管理

    嵌入式裸机内存动态管理实现与讲解(一)C 的标准库自带了malloc和free,为啥还要自己实现?标准库的函数占用空间较大,采用本文的
    发表于 12-17 07:02

    基于对象存储中的元数据组织管理方法

    提出了一种动态分区元数据组织管理方法它混合了动态和静态的方法在MDS 机群中分布元数据并使用散列的技术索引元数据利用共享存储来存放元数据整个
    发表于 06-28 17:03 53次下载
    基于对象<b class='flag-5'>存储</b>中的元数据组织<b class='flag-5'>管理方法</b>

    XXTEA加密算法的KEIL C实现

    本内容提供了XXTEA加密算法的KEIL C实现,详细列出了程序共大家学习
    发表于 08-25 17:57 3304次阅读

    keil C51 uVision2安装方法

    keil C51 uVision2安装方法
    发表于 11-03 10:27 7次下载

    Keil-C51与MDK-ARM并存方法

    Keil-C51与MDK-ARM并存方法
    发表于 03-14 17:45 21次下载

    基于C/S医疗设备全过程动态管理信息系统

    设计一套医疗设备的全过程动态管理信息系统。方法分析系统的整体框架,将系统分成购置管理、资产管理
    发表于 12-05 10:57 0次下载
    基于<b class='flag-5'>C</b>/S医疗设备全过程<b class='flag-5'>动态</b><b class='flag-5'>管理</b>信息系统

    基于对象跟踪的动态分析方法

    Web程序的安全威胁主要是由外部输入未验证引发的安全漏洞,如数据库注入漏洞和跨站脚本漏洞,动态污点分析可有效定位此类漏洞。提出一种基于对象跟踪的动态分析
    发表于 01-05 16:21 0次下载
    基于对象跟踪的<b class='flag-5'>动态</b><b class='flag-5'>分析</b><b class='flag-5'>方法</b>

    Keil C51单片机变量的使用方法详细介绍

    8051内核单片机是一种通用单片机,在国内占有较大的市场份额。在将C语言用于51内核单片机的研究方面,Keil公司做得最为成功。由于51内核单片机的存储结构的特殊性,Keil
    发表于 11-24 10:20 4634次阅读
    <b class='flag-5'>Keil</b> <b class='flag-5'>C</b>51单片机变量的使用<b class='flag-5'>方法</b>详细介绍

    keil C51应用程序和安装方法

    keil C51应用程序和安装方法
    发表于 11-27 08:00 11次下载

    如何在KEIL C实现直接寻址和间接寻址

    本文档的主要内容详细介绍的是如何在KEIL C实现直接寻址和间接寻址。
    发表于 07-02 17:42 0次下载
    如何在<b class='flag-5'>KEIL</b> <b class='flag-5'>C</b>中<b class='flag-5'>实现</b>直接寻址和间接寻址

    怎么样才能使用Keil C51开发大型嵌入式程序

     结合在8051系列单片机平台上的实际开发应用的经验,介绍用 Keil C在8051单片机上进行大型嵌入式程序开发的技术。主要阐述了大型嵌入式开发中在存储器的管理
    发表于 07-01 08:00 12次下载
    怎么样才能使用<b class='flag-5'>Keil</b> <b class='flag-5'>C</b>51开发大型嵌入式程序

    Keil5中C51和MDK共存的方法(以Keil5为例)

    Keil5中C51和MDK共存的方法(以Keil5为例)
    发表于 12-03 20:21 75次下载
    <b class='flag-5'>Keil</b>5中<b class='flag-5'>C</b>51和MDK共存的<b class='flag-5'>方法</b>(以<b class='flag-5'>Keil</b>5为例)

    Keil MDK与Keil C51共存的方法(成功)

    Keil5+Keil4共存的方法。在网上搜的资料MDK与KeilC51安装顺序都搞反了,但是用此安装方法可以成功解决了MDK与KeilC51的共存问题。所有功能完美运行。注意事项因为MDK功能比KeilC51多,所以要先安装Ke
    发表于 12-03 20:36 46次下载
    <b class='flag-5'>Keil</b> MDK与<b class='flag-5'>Keil</b> <b class='flag-5'>C</b>51共存的<b class='flag-5'>方法</b>(成功)