移动 - 黄烨明 - 基于VxWorks的内存管理和一个内存泄漏查找实例(4)

2019-03-22 12:57

及其对应的内存队列,根据队列的头, 将可用数据块的指针值返回给调用者。内存管理系统的初始化以及内存申请的算法如下图所示:

内存管理系统初始化创建内存管理队列信号量二级循环,初始化内存池对每个UB_POOL创建UB池队,调用CeateQueue() 申请内存块操作判断是否申请空内存,如果不是则继续执行信号量P操作成功为每个队列中的内存块分配内存并初始化根据申请内存大小得到一级索引分配之后加入队列AppendQueue()找到相应的内存池(UBPOOL)二级循环初始化内存存取索引表从内存池中取出内存地址返回返 回

内存初始化和内存申请算法

chapter 3 一个内存泄漏定位实例

在联调过程中,由于我们的设备必须长时间不间断运行,如果某个模块出现了内存泄漏,将会导致系统可用内存越来越少,最终导致系统瘫痪。本文对前几天MCU版软件出现的内存泄漏故障,以及故障的定位及解决办法作了一个总结,供参考。

故障现象:所有的NBAP消息编解码失败,原因是申请不到动态内存。 分析及解决步骤:

1、 首先判断是否是NBPS子系统引起

由于故障的直接表现是在NBPS子系统,而且NBPS子系统使用动态内存很频繁,因此应首先判断是不是由于NBAP编解码部分引起内存泄漏。

16

由于在此之前,NBAP编解码部分已经经过较长时间考验,在WINDOWS+VC平台长期运行,未发现内存泄露的现象;编解码部分的内存申请、释放都围绕编解码上下文进行(由购买的软件实现)。在此之前,NBAP编解码上下文的申请、释放都已经进行计数,而且经过长时间观察,释放与申请的个数完全一致。同时,观察内存泄露的规律,在较长时间未运行编解码程序的情况下,也存在泄漏,因此可基本排除NBPS子系统。

为了进一步确认,将NBAP编解码申请内存的函数该为了malloc,但是仍然存在内存泄漏。因此故障肯定在其他模块。

2、 确定泄漏的内存块大小

在采用OSS的环境中,例如MCU板,内存的分配、释放采用OSS提供的原语VmGetUB、VmRetUB实现。OSS管理的内存实在系统启动时一次性分配好的,根据实际系统的需求,将一次性申请到的内存划分为大小不等的内存池,每个内存池管理不通大小的内存块。内存的信息保存在全局数组atUBPool中。系统提供了函数QueueSize来获取某一个内存池中还可以分配的块数。

通过检查系统的内存池中身下的内存块数量,可以确认系统是否存在内存泄漏,并定位哪一个内存池出现了泄漏。例如,我们可以写如下的函数:

void ShowUB() { }

在系统刚启动时,执行一下此函数,可以打印出初始状态下系统应该剩下的内存块数。系统运行一段时间以后,在执行一下此函数,将打印结果进行比较,如果某个内存池出现可用块数减少,则可判断此内存池出现了泄漏。确定了是哪个内存池出现了泄漏,再根据系统的内存块定义表确定申请内存的大小范围。

在实际执行过程中,确定POOL 5出现了泄漏,根据内存块定义,可以确定泄漏的内存块大小介于1024~2048之间。

3、 定位预备泄漏的内存对应的分配内存的程序,找出有嫌疑模块

为了确定内存泄漏的模块,需要修改VmGetUB函数,使其可以判断当有程序申请的内存

BYTE }

byLoop;

\

pool

%d

Queue

size=%d.\\n\

(int)byLoop,

for ( byLoop = 0; byLoop < UBPOOL_SIZE ; byLoop ++){

printByUdp(9,

(int)QueueSize( atUBPool[byLoop]) );

17

大小在我们关心的范围内,就打印出调用模块。

具体实现方法:

首先,将VmGetUB函数改为VmGetUB1,增加文件名和行号两个输入参数: void _FAR * VmGetUB1(char * file, int line, WORD wSize);

其中,file为调用者的所在文件名,line为调用者的语句行号;在函数体中对申请的内存大小进行判断,如果大小介于我们关心的范围,就打印出file 和 line;

然后,将OSS的头文件中的VmGetUB函数原型去掉,改为如下宏定义: #define VmGetUB(wSize) VmGetUB1(__FILE__, __LINE__, wSize)

重新编译运行之后,可以打印出所有申请内存的地方。这些地方都是由嫌疑的模块。 实际运行中发现,申请内存大小介于1024~2048范围内的模块只有HDLC,申请的大小为2044。

4、 针对有嫌疑的模块,确认其是否存在泄漏。

为了确认某个具体的模块是否确实存在内存泄漏,可以另外写一个内存申请、释放函数,在函数中进行申请、释放计数。如果运行一段时间之后,发现释放数量与申请数量不符,则可以断定其为故障模块。

由于HDLC模块存在着由OSS申请、HDLC释放的情况(即对HdlcASend函数的调用),因此对申请的计数必须包括OSS调用HdlcASend的次数。

经过观察,发现在BPU由正常转为故障之后,HDLC模块释放的数量少于申请的数量,而且差值随着时间不断增加,差值刚好等于系统中泄露的内存块数。

以上描述的是采用OSS内存管理的模块的故障定位。有的模块不能采用OSS内存管理,需要采用操作系统的malloc。这种情况下,也可以自定义一个内存申请、释放函数,然后将malloc采用替换的方式或者采用宏定义的方式替换为自定义的函数,达到对申请、释放进行计数的目的。

最后,还是建议编码过程中,最好能对内存的申请、释放集中在一起进行操作,而不要分散到整个模块,甚至多个文件之中,以代码走读查错和便于进行故障定位。

18


移动 - 黄烨明 - 基于VxWorks的内存管理和一个内存泄漏查找实例(4).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:《遗传学》教学大纲 - 图文

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: