访问手机版页面
你的位置:老古开发网 > 51单片机 > 51单片机Keil C51编程 > 正文  
Keil C动态内存管理机制分析及改进
内容导读:
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版,将其中与动态存储管理相关的数据结构介绍如下:

  该结构的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函数已被成功调用过,此时函数直接返回。

标签:
来源:单片机及嵌入式系统应用 作者:重庆电力高等专科学校 丁明亮 熊真春 时间:2007/7/4 0:00:00
相关阅读
推荐阅读
阅读排行
最近更新
商品推荐