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

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

3天内不再提示

动态内存管理模块的设计原理与实现

电子设计 来源:单片机与嵌入式系统应用 作者:徐文 2020-06-30 08:05 次阅读

引言

当前,绝大多数嵌入式平台上的软件都采用C语言编写。除了代码简洁、运行高效之外,灵活操作内存的能力更是C语言的重要特色。然而,不恰当的内存操作通常也是错误的根源之一。如“内存泄漏” ――不能正确地释放已分配的动态内存,就是一种非常难于检测的存错误。持续的内存泄漏会使程序性能下降到最终完全不能运行,进而影响到所有其它有动态内存需求的程序,在某些相对简单的嵌入式平台上甚至会妨碍操作系统的运转。再如“写内存越界”,一种不合法的写内存操作,极可能破坏到本程序中正在使用的其它数据,严重的时候还可能对其它正在运行的程序甚至整个系统造成影响。为此,本文介绍一个增强的、可定制的动态内存管理模块(以下不妨简称Fense),在 C语言提供的内存分配函数基础上,增加了对动态内存的管理功能;能记录软件运行过程中出现的内存泄漏信息,同时也具一定的监测内存操作的能力;可以发现绝大多数对动态内存的写越界错误。

1、Fense的设计原理

Fense 通过设立一个双向链表(struct Head *stHead)来保存所有被分配的动态内存块的信息。链表中的每个节点对应一个动态内存块,节点中包括此内存大小、分配发生时所在的源文件名和行号以及被释放的时候,Fense又从st_Head中删除之,检查st_Head中的节点即可得到未被释放的本节点的数值校验和等。Fense将每一个分配的动态内存块插入到链表st_Head中;当此内存放内存块信息。链表节点结构定义如下:

struct Head{

char file; /分配所在源文件名*/

unsigned long line; /*分配所在的行号*/

size_t size; /*分配的内存大小*/

int checksum; /*链表节点校验和*/

struct Head prev,next; /*双链表的前后节点指针*/

};

/*全局的双向链表*/

struct Head *st_Head=NULL;

为了检测写越界的错误,Fense在用户申请的内存前后各增加了一定大小的内存作为监测区域,并初始化成预定值。这样,当程序发生越界写操作时,预定值就会发生改变,Fense即可检测到错误。

通过Fense分配到的动态内存结构如图1所示。由此可知,Fense_Malloc(Fense的内存分配函数)返回给用户的指针ptr指向的是用户申请内存区域的起始位置。链表节点、前/后监测区域均为Fense内部使用,是用户不可见的。

动态内存管理模块的设计原理与实现

2、 用户定制选项

Fense有5组宏定义提供给用户对功能进行定制。各组选项控制意义如下:

WARN_ON_ZERO_MALLOC 用户申请零分配空间时警告信息。

FILL_ON_MALLOC 分配时初始化内存块

FILL_ON_MALLOC_VAL 分配初始化时的预设值

FILL_ON_FREE 释放时填充内存块

FILL_ON_FREE_VAL 释放时填充内存块的预设值

以上4个选项的主要功能是初始化刚分配到的内存和刚被释放的内存为预设值,尽可能地避免出现因使用未初始经的内存而引发的错误。

FENSE_FRONT_SIZE 定义前监测区域大小

FENSE_FRONT_VAL 定义前监测区域的预设值

FENSE_END_SIZE 定义后监测区域大小

FENSE_END_VAL 定义后监测工域的预设值

在Fense 工作过程中,对内存越界写操作的检验是通过比较监测区域的当前值与本监测区域的预设值来确定的。显然不能排除这样一种可能:即发生在监测区域的越界写操作写入的数值与监测区域的预设值恰好相同,此时,Fense无法发现错误的发生。对于这种情况,用户可以通过更改监测区域预设值(FENSE_FRONT_VAL和FENSE_END_VAL)和监测区域大小(FENSE_FRONT_SIZE和FENSE_END_SIZE)为多组不同的值来反复测试,这样就可以大幅度地提高监测的准确性。

VALIDATE_FREE

free是检查本内存块是否在链表中

CHECK_ALL_MEMORY_ON_FREE

free时检查链表中的所有内存块

由于存在这样一种情况:对内存块A的写操作出现了越界错误,写到了另一内存块B的区域内。此时,仅仅检查内存块A的有效性就无法发现问题,如果同时检查所有的动态内存块,则有可能发现错误所在。以上选项即为此而设。

FENSE_LOCK 获取对链表st_Head的操作权

FENSE_UNLOCK 释放对链表st_Head的操作权

考虑到的在多线程环境中,可能有多个线程同时用Fense进行内存管理,而Fense使用的链表st_Head是全局变量,因此提供了以上2个宏来实现对 st_Head的互斥访问。宏的具体定义依赖于用户所在的软件环境,用户可自行实现。对于单线程系统,仅需将这2个宏定义为空即可。

为便于使用,Fense的头文件中还包括了以下定义,使得用户基本不用改动现有的源代码就可引入Fense。

#define malloc(size) Fense_Malloc(size,_FILE_,_LINE_)

#define free(ptr) Fense_Free(ptr,_FILE_,_LINE_)

#define realloc(ptr,new_size) Fense_Realloc(ptr,new_size,_FILE_,_LINE_)

#define colloc(num,size) Fense_Calloc(num,size,_FILE_,_LINE_)

3、 运行时控制

Fense 监测内存的功能可以在运行动态地开关。此功能通过将全局变量st_Disbaled赋值为零或非零来实现。在调试过程中,可以在调试器中即时修改 st_Disabled的值来控制Fense的行为,省去了重编译源代码的需要。对于那些需要大量编译时间的大型工程或交叉平台开发的软件项目来说,这是非常有利的。

4、 Fense的具体实现

Fense 提供Fense_Malloc、Fense_Free、Fense_Realloc及Fense_Calloc等内存管理函数,功能和调用形式与C语言中的malloc、free、realloc和calloc保持一致。限于篇幅,这里仅对Fense_Malloc和Fense_Free的实现过程做一个简单描述,具体实现请见本刊网络补充版。http://www.dpj.com.cn

/*内存分配函数*/

void *Fense_Malloc(size_t size,char *file,unsigned long line)

{

//检查Fense的运行时开关,如果Fense被关闭,则调用malloc

//分配并返回

//检查是否零分配,如有则提示警告信息后返回0(用户定制选项)

//分配内存,包括链表节点区域和前/后监测区域

//初始化链表节点,保存分配内存的信息,包括分配的大小、所在文件名和行号

//将此节点插入链表st_Head

//为本节点区域计算校验和

//用预设值初始化前/后监测区域

//用预设值填充用户内存区域(用户定制选项)

//返回用户内存区域的起始位置

}

/*内存释放函数*/

void Fense_Free(void *uptr,char *file,unsigned long line)

{

//检查Fense的运行时开关,如果Fense初关闭,则调用free释译并返回

//检查所有Fense管理下的动态内存(用户定制选项)

//判断当前内存块是否在链表st_Head中,如果不在则提示

//警靠信息,退出(用户定制选项)

//检查当前内存块是否存在越界操作

//将当前内存块的相应的链表节点从st_Head中删除

//重新计算当前节点的前后相邻节点的校验和

//用预设值填充被释放的内存区(用户定制选项)

//调用free释放当前的内存块

}

(文中代码在Visual C++6.0、Borland C++ 3.1及CrossCode C 7.4环境中编译通过)

5、结束语

作为对C程序运行时的内存错误进行监测的代码模块,Fense能发现几乎所有的内存泄漏和绝大多数的越界操作,并尽可能地记录了改正程序错误所需要的信息;有效地减少了程序设计人员的调试时间,在实际嵌入式产品开发中取得了很好的效果。

责任编辑:gt


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

    关注

    4981

    文章

    18273

    浏览量

    288338
  • 内存
    +关注

    关注

    8

    文章

    2766

    浏览量

    72752
  • 操作系统
    +关注

    关注

    37

    文章

    6280

    浏览量

    121869
收藏 人收藏

    评论

    相关推荐

    C语言程序设计中动态内存分配如何实现

    C语言程序设计中,动态内存分配如何实现,需要注意哪些问题?
    发表于 09-28 16:53 846次阅读

    第28章 FreeRTOS动态内存管理

    28.4 实验例程说明28.5总结28.1动态内存管理介绍 FreeRTOS支持5种动态内存管理方案,分别通过文件heap_1,heap_2,heap_3,heap_4和heap_5
    发表于 09-11 07:15

    arduino 动态内存不足怎么处理

    arduino Mega2560 加入第一个 Serial 串口 ,动态内存是2000 字节, 加入第2个Serial 串口 动态内存是 4000字节, 现在我需要加入第3个Serial 串口 , 动态内存是 6000字节, 再
    发表于 06-18 08:29

    动态内存管理的原理详解

    C/C++语言与其他语言不同,它需要开发者自己管理内存资源。对于动态内存的使用不当容易造成段错误或者内存泄漏。尤其是内存泄漏,
    发表于 11-02 09:25

    请问怎样去设计Fense动态内存管理模块

    Fense的设计原理是什么?Fense有哪些功能?怎样去设计Fense动态内存管理模块
    发表于 04-26 07:18

    内存动态内存分配实现

    第27章 STM32H7的TCM,SRAM等五块内存动态内存分配实现本章教程为大家分享一种DTCM,SRAM1,SRAM2,SRAM3和SRAM4可以独立管理
    发表于 08-03 07:14

    动态内存管理该怎样去移植呢

    动态内存管理该怎样去移植呢?如何去使用动态内存呢?
    发表于 10-09 06:04

    使用动态内存分配安全吗

    [导读]想在C语言程序员之间开始一个激烈的,或者说有争议的讨论很简单,只需要问:“使用动态内存分配安全吗?”想在C语言程序员之间开始一个激烈的,或者说有争议的讨论很简单,只需要问:“使用动态内存分配
    发表于 12-15 07:44

    动态内存分配是什么意思

    所谓动态内存分配(Dynamic Memory Allocation)就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态
    发表于 12-17 08:17

    动态内存管理是什么?动态内存管理算法有哪几种

    详细描述动态内存堆接口动态内存管理是一个真实的堆内存管理模块,可以在当前资源满足的情况下,根据用
    发表于 08-29 15:23

    一个动态内存管理模块实现

    介绍一个动态内存管理模块,可以有效地检测C程序中内存泄漏和写内存越界等错误,适用于具有标准C 语言开发环境的各种平台。
    发表于 04-16 14:18 14次下载

    一个动态内存管理模块实现

    介绍一个动态内存管理模块,可以有效地检测C程序中内存泄漏和写内存越界等错误,适用于具有标准C 语言开发环境的各种平台。
    发表于 05-14 14:39 10次下载

    动态内存错误的静态检测

    内存泄漏、空指针引用等动态内存错误在/,/LL等支持动态内存操作的程序中普遍存在在程序中,动态内存管理错误是导致
    发表于 06-10 16:29 52次下载
    <b class='flag-5'>动态内存</b>错误的静态检测

    嵌入式C语言中的动态内存管理动态内存分配

    动态内存管理同时还具有一个优点:当程序在具有更多内存的系统上需要处理更多数据时,不需要重写程序。
    发表于 08-15 17:16 1980次阅读

    C语言中的动态内存管理讲解

    本章将讲解 C 中的动态内存管理。C 语言为内存的分配和管理提供了几个函数。这些函数可以在 头文件中找到。
    的头像 发表于 02-23 14:03 150次阅读
    C语言中的<b class='flag-5'>动态内存</b><b class='flag-5'>管理</b>讲解