基于LTE协议栈的内存池问题定位方法及其系统与流程

文档序号:12801787阅读:186来源:国知局
基于LTE协议栈的内存池问题定位方法及其系统与流程

本发明涉及内存管理技术领域,尤其涉及一种基于lte协议栈的内存池问题定位方法及其系统。



背景技术:

在c语言环境下,内存的分配和释放,可以直接使用系统申请/释放函数接口。但是有以下弊端:

1、调用系统函数,相对比较耗时;

2、频繁使用会产生大量的内存碎片,从而降低程序运行效率。

为了避免以上问题,在项目中一般使用内存池来代替系统函数进行内存管理。内存池的初始结构如图1所示,在真正使用内存之前,预先分配一定数量的内存块,当需要申请内存时,就从这些预先分配的内存块中选择,而不是直接使用系统函数进行分配。内存块被分配后,如图2所示。

内存池算法一般关注于管理内存(分配算法、释放算法、不定长内存块算法等),而没有关注于内存池的稳定,即快速定位内存池泄露、内存块使用时越界问题。

内存池泄露是指在从内存池分配一个内存块后,应该被释放而没有被释放的情况;内存块使用时越界与数组越界类似,比如向10字节大小的内存块写入20字节的数据。内存池泄露会导致内存最后耗尽,而越界则会导致程序运行不稳定。良好的编程习惯可以预防一部分的内存池泄露、越界等问题,但是,随着项目代码量的增加以及多人协作,完全避免几乎是不可能做到的。内存泄露和数组越界很容易引入,而难以定位,尤其是代码量庞大、多线程的环境中更难以定位。

一般,使用mtrace、valgrind定位内存泄露。而对于越界,则更难以处理,例如下述的代码:

程序编译时并不能发现,且在程序运行时并不一定会发生,只有在外部输入超过10个字符的时候才会发生越界。

对于lte协议栈,由于接入层的时序要求,它的调度周期是1毫秒,即在每1个毫秒内,必须完成接入设备的调度、资源的分配、编码等等,所以,lte协议栈的时序要求十分严格,即使在嵌入式环境下mtrace、valgrind可以移植使用,在跑lte协议栈时使用不了,它会严重影响协议栈的运行性能,导致不能正常工作。

在公开号为cn105988921a的中国专利公开文件中,提出了一种内存越界的检测方法及装置,其方法包括:获取分配给待检测程序的内存块的起始地址和内存管理头信息,内存管理头信息包括:内存块的容量以及释放标记;检测释放标记,若释放标记指示内存块已被释放,则判断待检测程序发生内存越界;若释放标记指示内存块未被释放,则获取待检测程序的第一偏向地址,第一偏向地址为距起始地址最远的偏向地址;根据内存块的容量和起始地址,检测第一偏向地址是否落在内存块的内存范围内;若第一偏向地址未落在内存块的内存范围内,则判断待检测程序发生内存越界。但该方案的越界定位准确率不高,例如,物理上连续的内存块1-4,假设在内存块1越界并修改内存块2-4的内容,该方案找出的可能是内存块4的越界。



技术实现要素:

本发明所要解决的技术问题是:提出一种基于lte协议栈的内存池问题定位方法及其系统,可快速定位出内存泄露位置和内存越界位置。

为了解决上述技术问题,本发明采用的技术方案为:一种基于lte协议栈的内存池问题定位方法,包括:

在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值;

若一内存块被分配,则将所述一内存块的分配标记设置为预设的对应已分配的第一字符,将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

当所述一内存块被释放后,将所述一内存块的分配标记设置为预设的对应未分配的第二字符;

当所述一内存块重新放入内存池时,分别检测所述一内存块的第一标记和第二标记是否与预设的参数值一致;

若所述一内存块的第一标记与其预设的参数值一致且第二标记与其预设的参数值不一致,则判定所述一内存块越界;

根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置;

若内存池的使用率超过预设的阈值,则获取分配标记为第二字符的内存块;

根据所获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置。

本发明还涉及一种基于lte协议栈的内存池问题定位系统,包括:

第一设置模块,用于在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值;

第二设置模块,用于若一内存块被分配,则将所述一内存块的分配标记设置为预设的对应已分配的第一字符,将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

第三设置模块,用于当所述一内存块被释放后,将所述一内存块的分配标记设置为预设的对应未分配的第二字符;

检测模块,用于当所述一内存块重新放入内存池时,分别检测所述一内存块的第一标记和第二标记是否与预设的参数值一致;

判定模块,用于若所述一内存块的第一标记与其预设的参数值一致且第二标记与其预设的参数值不一致,则判定所述一内存块越界;

第一定位模块,用于根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置;

获取模块,用于若内存池的使用率超过预设的阈值,则获取分配标记为第二字符的内存块;

第二定位模块,用于根据所获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置。

本发明的有益效果在于:通过在内存块中加入记录该内存中分配状态的分配标记,以及记录申请该内存块的函数名和函数位置的字符串指针和位置变量,即可在内存泄露,即内存池中超过预设个数的内存块都处于分配状态时,快速地定位出内存泄露的位置;同时,在内存块的头尾分别加入第一标记和第二标记,可在内存块释放时,通过检测第一标记和第二标记来判断该内存块是否发生越界,定位到发生越界的内存块,再根据该内存块所记录的函数名和函数位置,定位到内存越界的具体位置;本发明可在满足lte严格时序要求,不影响协议栈正常工作的情况下(每毫秒增加耗时1微妙以内,即影响在千分之1以内)解决内存池的内存泄露及内存越界问题。

附图说明

图1为现有技术的内存池结构示意图;

图2为现有技术的内存块被分配后的示意图;

图3为本发明一种基于lte协议栈的内存池问题定位方法流程图;

图4为本发明实施例一的内存池泄露的定位方法流程图;

图5为本发明实施例一的步骤s106的方法流程图;

图6为本发明实施例一的内存块越界的定位方法流程图;

图7为本发明实施例一的步骤s206的方法流程图;

图8为本发明实施例一的内存块结构示意图;

图9为本发明实施例二的方法流程图;

图10为本发明实施例二的内存池结构示意图;

图11为本发明实施例二的内存块分配示意图;

图12为本发明实施例二的内存块释放示意图;

图13为本发明实施例三分配前后的内存块结构示意图;

图14为本发明实施例三内存池情况示意图;

图15为本发明实施例三内存块越界前后对比示意图;

图16为一种基于lte协议栈的内存池问题定位系统的结构示意图;

图17为本发明实施例四的系统结构示意图。

标号说明:

1、第一设置模块;2、第二设置模块;3、第三设置模块;4、检测模块;

5、判定模块;6、第一定位模块;7、获取模块;8、第二定位模块;9、定义模块;10、放入模块;11、连接模块;12、申请模块;13、分配模块;

14、第一指向模块;15、确定模块;16、第二指向模块;

61、第一获取单元;62、第二获取单元;63、第三获取单元;64、第一定位单元;

81、第四获取单元;82、第五获取单元;83、第二定位单元。

具体实施方式

为详细说明本发明的技术内容、所实现目的及效果,以下结合实施方式并配合附图详予说明。

本发明最关键的构思在于:在内存块的头尾加入标记以及记录申请该内存块的函数名和函数位置的字符串指针和位置变量。

请参阅图3,一种基于lte协议栈的内存池问题定位方法,包括:

在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值;

若一内存块被分配,则将所述一内存块的分配标记设置为预设的对应已分配的第一字符,将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

当所述一内存块被释放后,将所述一内存块的分配标记设置为预设的对应未分配的第二字符;

当所述一内存块重新放入内存池时,分别检测所述一内存块的第一标记和第二标记是否与预设的参数值一致;

若所述一内存块的第一标记与其预设的参数值一致且第二标记与其预设的参数值不一致,则判定所述一内存块越界;

根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置;

若内存池的使用率超过预设的阈值,则获取分配标记为第二字符的内存块;

根据所获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置。

从上述描述可知,本发明的有益效果在于:可在满足lte严格时序要求,不影响协议栈正常工作的情况下,解决内存池的内存泄露及内存越界问题。

进一步地,所述“根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置”具体为:

根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,获取申请所述一内存块的第一代码位置;

根据gdb或backtrace函数获取函数栈信息;

根据所述函数栈信息,获取释放所述一内存块的第二代码位置;

根据所述第一代码位置和第二代码位置,定位内存越界的位置。

由上述描述可知,通过获取申请发生越界的内存块的位置以及释放发生越界的内存块的位置,即定位出线索的头尾,由此即可定位到发生越界的具体位置。

进一步地,所述“根据所述获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置”具体为:

获取分配标记为第二字符的内存块的字符串指针记录的函数名以及位置变量记录的行数;

获取所述函数名和行数中出现次数最多的函数名和行数;

根据所获取的函数名和行数,定位内存泄露位置。

由上述描述可知,通过记录申请内存块的函数及函数代码位置,在内存池泄露发生时,查看没有释放的内存块中,哪个函数出现的次数异常多,即可确认该函数发生了内存泄露。

进一步地,所述“在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值”之前,进一步包括:

定义两组以上不同大小的内存块,其中,同一组内的各内存块的大小一致;

将同一组的内存块按照预设的顺序放入同一内存池,并将所述内存池的链表头指针指向最后放入的内存块,将所述内存池的链表尾指针指向最先放入的内存块;

将各内存池的链表头指针和链表尾指针通过数组进行连接;

申请内存时,选择内存块大小与所申请的内存大小最接近的内存池;

内存块分配时,将所述内存池中的第一个内存块作为被分配的内存块从链表中删除,将所述内存池中的第二个内存块的next指针指向空,将链表尾指针指向所述第二个内存块;

将被分配的内存块的next指针指向链表头;

内存块释放时,根据其所指向的链表头,确定对应的内存池;

将被释放的内存块的next指针指向对应的内存池中的最后一个内存块,并将所述内存池的链表头指针指向所述内存块。

由上述描述可知,对内存池的操作,只有改变2-4个链表指针的操作,有效地提高了内存池的处理效率。

请参照图16,本发明还提出了一种基于lte协议栈的内存池问题定位系统,包括:

第一设置模块,用于在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值;

第二设置模块,用于若一内存块被分配,则将所述一内存块的分配标记设置为预设的对应已分配的第一字符,将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

第三设置模块,用于当所述一内存块被释放后,将所述一内存块的分配标记设置为预设的对应未分配的第二字符;

检测模块,用于当所述一内存块重新放入内存池时,分别检测所述一内存块的第一标记和第二标记是否与预设的参数值一致;

判定模块,用于若所述一内存块的第一标记与其预设的参数值一致且第二标记与其预设的参数值不一致,则判定所述一内存块越界;

第一定位模块,用于根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置;

获取模块,用于若内存池的使用率超过预设的阈值,则获取分配标记为第二字符的内存块;

第二定位模块,用于根据所获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置。

进一步地,所述第一定位模块包括:

第一获取单元,用于根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,获取申请所述一内存块的第一代码位置;

第二获取单元,用于根据gdb或backtrace函数获取函数栈信息;

第三获取单元,用于根据所述函数栈信息,获取释放所述一内存块的第二代码位置;

第一定位单元,用于根据所述第一代码位置和第二代码位置,定位内存越界的位置。

进一步地,所述第二定位模块包括:

第四获取单元,用于获取分配标记为第二字符的内存块的字符串指针记录的函数名以及位置变量记录的行数;

第五获取单元,用于获取所述函数名和行数中出现次数最多的函数名和行数;

第二定位单元,用于根据所获取的函数名和行数,定位内存泄露位置。

进一步地,还包括:

定义模块,用于定义两组以上不同大小的内存块,其中,同一组内的各内存块的大小一致;

放入模块,用于将同一组的内存块按照预设的顺序放入同一内存池,并将所述内存池的链表头指针指向最后放入的内存块,将所述内存池的链表尾指针指向最先放入的内存块;

连接模块,用于将各内存池的链表头指针和链表尾指针通过数组进行连接;

申请模块,用于申请内存时,选择内存块大小与所申请的内存大小最接近的内存池;

分配模块,用于内存块分配时,将所述内存池中的第一个内存块作为被分配的内存块从链表中删除,将所述内存池中的第二个内存块的next指针指向空,将链表尾指针指向所述第二个内存块;

第一指向模块,用于将被分配的内存块的next指针指向链表头;

确定模块,用于内存块释放时,根据其所指向的链表头,确定对应的内存池;

第二指向模块,用于将被释放的内存块的next指针指向对应的内存池中的最后一个内存块,并将所述内存池的链表头指针指向所述内存块。

实施例一

本发明的实施例一为:一种基于lte协议栈的内存池问题定位方法,主要对内存池泄露和内存越界进行检测并定位。

其中,如图4所示,内存池泄露的定位方法包括如下步骤:

s101:在内存块的头部设置分配标记、字符串指针和位置变量;

s102:若一内存块被分配,则将所述一内存块的分配标记设置为预设的对应已分配的第一字符,将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

s103:当所述一内存块被释放后,将所述一内存块的分配标记设置为预设的对应未分配的第二字符;

s104:判断内存池的使用率是否超过预设的阈值,若是,则执行步骤s105。

s105:获取分配标记为第二字符的内存块;

s106:根据所获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置。

其中,如图5所示,所述步骤s106包括如下步骤:

s1061:获取分配标记为第二字符的内存块的字符串指针记录的函数名以及位置变量记录的行数;

s1062:获取所述函数名和行数中出现次数最多的函数名和行数;

s1063:根据所获取的函数名和行数,定位内存泄露位置。

本实施例对于内存池泄露定位,基于一个合理的假设:内存池泄露是在程序中某个位置申请了内存,而没有释放,且没有释放的次数异常得多。在程序中,可能有非常多的位置申请了内存,经过一段处理后,在无bug存在的情况下,都会被释放,即在正常运行时,未释放的内存数量是一个动态稳定的,比如正常运行时,内存池中未释放的内存块占比在60%以内。而在发生内存池泄露时,可能达到100%,最后,发生无可分配内存的情况。那么,在发生内存泄露时,40%的内存是程序中某个位置申请了内存,而没有释放。找出这40%的内存是在哪个函数哪个位置申请的,就可以定位,即实现mtrace的功能(如果在时序要求不严格的情况下,用mtrace即可)。

因此,通过记录申请内存块的函数及函数代码位置,在内存池泄露发生时,查看没有释放的内存块中,哪个函数出现的次数异常多,即可确认该函数发生了内存泄露。

如图6所示,内存块越界的定位方法包括如下步骤:

s201:在内存块的头部设置第一标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值;

s202:若一内存块被分配,则将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

s203:当所述一内存块重新放入内存池时,分别检测所述一内存块的第一标记和第二标记是否与预设的参数值一致;

s204:判断所述一内存块的第一标记是否与其预设的参数值一致且第二标记与其预设的参数值不一致,若是,执行步骤s205。

s205:判定所述一内存块越界;

s206:根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置。

其中,如图7所示,步骤s206包括如下步骤:

s2061:根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,获取申请所述一内存块的第一代码位置;

s2062:根据gdb或backtrace函数获取函数栈信息;

s2063:根据所述函数栈信息,获取释放所述一内存块的第二代码位置;

s2064:根据所述第一代码位置和第二代码位置,定位内存越界的位置。

由于程序一般很大,所以在发生内存越界时分析所有的代码以找出bug位置很难,内存块越界定位的目标是找出发生内存越界时的那个位置即bug位置。内存块的越界定位一般是通过将出现bug的范围缩小到一个很小的范围,缩小的范围越小则越好。现有的定位内存块越界的方式是用mprotect将内存页设置成不可读写,其可以将越界范围缩小到唯一的一个位置即bug位置,是目前最好的内存块越界定位方式。但在lte协议栈中,由于时序及内存大小的限制(由于mprotect操作的最小单位是一个内存页,即4k字节大小,内存块小于4k时,内存块由2个内存页组成,13万个内存块就需要1g的内存,一般嵌入式设备由于成本考虑,其内存大小在满足需求后不会有太多剩余,假设内存块平均大小100字节计算,用mprotect则需要8192字节即增加80倍的内存),不能使用mprotect,所以,不能在发生内存越界时马上就能检测到。

本实施例对于内存块越界的定位,通过设置在内存块头部的第一标记和尾部的第二标记来判断该内存块是否发生越界。例如,一个内存池有4个物理上连续的内存块组成,顺序依次为链表头、内存块4、内存块3、内存块2、内存块1、链表尾;假设内存块大小均为8字节,除内存块4外,其他内存块均被分配出去;程序在使用内存块3时,使用了20字节,则会将连续的内存给改写了,即内存越界,内存块3越界,导致内存块1和内存块2的内容被改写(例如,改写为0)。

如果内存块1先释放,在放入内存池时,检测到其第一标记错误(即与其预设的参数值不一致),而第二标记正确(即与其预设的参数值一致),说明虽然内存块1发生了内存越界,但不是它引起的,所以忽略此内存越界(既不处理,也不放入内存池,因为此时它的头部信息已经不可信任)。

如果内存块2先于内存块3被释放,在放入内存池时,检测到其第一标记和第二标记都是错误的,说明也不是它造成的越界。

内存块3使用完后,放入链表时,检测到其第一标记正确(说明前面的内存块没有越界,即内存块4没有越界,是正常的),而第二标记错误,说明就是它发生了越界,此时使用gdb或者backtrace函数,定位发生内存越界后释放此内存块的位置,并结合内存池泄露定位方法加入的信息定位此内存块分配时的位置,即定位线索的头尾,由此即可定位到bug位置,其余一般在代码上即可排除(例如,某些位置只操作了此内存块的第1个字节,那么,内存越界肯定和它是无关的,可排除)。

根据上述内存池泄露的定位方法和内存块越界的定位方法,可以得知,在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值,即可同时对内存池泄露和内存块越界进行定位;具体地,内存块的示意图如图8所示,其中,magic1为第一标记,magic1为第二标记;alloced为分配标记;表示该内存块是否已分配的flag;next为内存块原有的指针,在内存块空闲时指向下一个空闲节点,在内存块被分配时指向内存池;char*为字符串指针,用于指向申请该内存块的函数的函数名字符串;int为位置变量,表示申请该内存块的代码在程序中所处的行数;其中,第一标记一定位于内存块最头部的位置,第二标记一定位于内存块最末尾的位置,分配标记、字符串指针和位置变量之间的顺序可互相调换。

本实施例通过在内存块中加入记录该内存中分配状态的分配标记,以及记录申请该内存块的函数名和函数位置的字符串指针和位置变量,即可在内存泄露,即内存池中超过预设个数的内存块都处于分配状态时,快速地定位出内存泄露的位置;同时,在内存块的头尾分别加入第一标记和第二标记,可在内存块释放时,通过检测第一标记和第二标记来判断该内存块是否发生越界,定位到发生越界的内存块,再根据该内存块所记录的函数名和函数位置,定位到内存越界的具体位置;可在满足lte严格时序要求,不影响协议栈正常工作的情况下(每毫秒增加耗时1微妙以内,即影响在千分之1以内)解决内存池的内存泄露及内存越界问题。

实施例二

请参照图9,本实施例是实施例一的进一步拓展。步骤s101和s201之前还包括如下步骤:

s001:定义两组以上不同大小的内存块,其中,同一组内的各内存块的大小一致;例如,定义三组内存块,大小分别为8字节、16字节和32字节,其中,第一组中的内存块的大小均为8字节,第二组中的内存块的大小均为16字节,第三组中的内存块的大小均为32字节。

s002:将同一组的内存块按照预设的顺序放入同一内存池,并将所述内存池的链表头指针指向最后放入的内存块,将所述内存池的链表尾指针指向最先放入的内存块;此时,可将第一组内存块放入的内存池记为8字节内存池,将第二组内存块放入的内存池记为16字节内存池,将第三组内存块放入的内存池记为32字节内存池。

s003:将各内存池的链表头指针和链表尾指针通过数组进行连接;此时得到的内存池结构如图10所示。

s004:申请内存时,选择内存块大小与所申请的内存大小最接近的内存池;进一步地,选择内存块大小大于所申请的内存大小且内存块大小与所申请的内存大小最接近的内存池;例如,所申请的内存大小为15字节时,则选择16字节内存池,而不选择32字节内存池;当所申请的内存大小为20字节,即使与16字节接近,但由于16字节小于20字节,因此需选择32字节内存池。

s005:内存块分配时,将所述内存池中的第一个内存块作为被分配的内存块从链表中删除,将所述内存池中的第二个内存块的next指针指向空,将链表尾指针指向所述第二个内存块;

s006:将被分配的内存块的next指针指向链表头;此时,该内存池中内存块分配的示意图如图11所示。

s007:内存块释放时,根据其所指向的链表头,确定对应的内存池;

s008:将被释放的内存块的next指针指向对应的内存池中的最后一个内存块,并将所述内存池的链表头指针指向所述内存块。此时,该内存池中内存块释放的结构示意图如图12所述。

本实施例对内存池的操作,只有改变2-4个链表指针的操作,如果是多线程,则需要加锁和解锁操作,因此本实施例有效地提高了内存池的处理效率。

实施例三

本实施例是对应上述实施例的一具体应用场景。本实施例以图8所示的内存块为例。

请参照图13,在分配前,char*和int位置无任何有效内容,alloced标记设置为0x22(表示未分配)。内存被分配后,alloced标记设置为0x11(表示已分配),char*和int位置存入的是调用函数名和位置。在释放后,alloced再次设置为0x22。其中有memleak变量指向的内存块出现了内存泄露,并未释放。正常运行时,在内存池中最多只会存在一个未释放的addr0、memleak、addr1内存块,即在内存池中,未释放的内存块中,testfunc函数最多只会存在3个。但是,由于memleak变量申请内存后,未释放,多次执行testfunc函数后,内存池的泄露就会越来越严重,直到影响程序运行。此时,查看内存池情况,如图14所示,内存池中总共由22个内存块组成,在正常运行时,最多只会出现3个内存被使用,即正常情况下,内存池的使用率是13%(3/22)。而在异常情况下,如图中所示,有16个内存被使用,即内存池的使用率是72%,可以确定发生了内存泄露。在发生泄露后,用gdb脚本(或者printf函数打印)将内存池中所有未释放的内存块中保存的函数名及位置打印出来即可发现,“testfunc”位置14出现的次数是14次,“testfunc”位置13和15的次数各1次,可以判断,“testfunc”位置14申请的内存发生了泄露,即定位在“testfunc”的14行,实现mtrace的功能。

对于内存块越界定位,请参照图15,其申请了3个内存块,且刚好物理上连续。由于在申请时是申请8个字节,而使用时是20个字节,导致越界。在程序中,addr0先于addr1和addr2分配而最后释放。在addr2释放时,检测到第一标记为0,是错误的,而第二标记是正确的,说明在物理上连续的前面内存块发生了越界且越界到此内存块为止,不处理addr2指向的内存块(因为它的next指针已损坏,不能指向正确的链表,所以不将其加入空闲内存块链表)。在addr1释放时,检测到第一标记和第二标记的标记都是错误的,说明是在物理上连续的前面内存块发生了越界且越界到此内存块以后,不处理addr1指向的内存。

在addr0释放时,检测到第一标记是正确的,而第二标记是错误的,说明此内存块发生了内存越界,据此,根据gdb或者backtrace函数获取函数栈信息,即可定位到testfunc函数中的26行,而根据保存在内存块的函数名和函数位置信息可知内存申请是在testfunc函数的13行(如果没有此信息,内存块释放对应的内存块申请位置可能有多个,即不同函数不同位置申请的内存块,可能在同一个位置释放),即内存越界发生在testfunc的13行到26行之间的某个位置,而在这位置之间只有testfunc的18行对addr0进行了操作,所以,就是它产生的内存越界,修改testfunc的18行的bug即可解决这个内存越界问题。

本实施例对内存池泄露和内存块越界的定位方法,都只需对几个标记进行赋值和判断,对性能的影响是可以忽略不计的。

实施例四

请参照图17,本实施例是对应上述实施例的一种基于lte协议栈的内存池问题定位系统,包括:

第一设置模块1,用于在内存块的头部设置第一标记、分配标记、字符串指针和位置变量,在内存块的尾部设置第二标记,所述第一标记和第二标记为预设的参数值;

第二设置模块2,用于若一内存块被分配,则将所述一内存块的分配标记设置为预设的对应已分配的第一字符,将所述一内存块的字符串指针设置为申请所述一内存块的函数名,将所述一内存块的位置变量设置为申请所述一内存块的代码所处的行数;

第三设置模块3,用于当所述一内存块被释放后,将所述一内存块的分配标记设置为预设的对应未分配的第二字符;

检测模块4,用于当所述一内存块重新放入内存池时,分别检测所述一内存块的第一标记和第二标记是否与预设的参数值一致;

判定模块5,用于若所述一内存块的第一标记与其预设的参数值一致且第二标记与其预设的参数值不一致,则判定所述一内存块越界;

第一定位模块6,用于根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存越界的位置;

获取模块7,用于若内存池的使用率超过预设的阈值,则获取分配标记为第二字符的内存块;

第二定位模块8,用于根据所获取的内存块的字符串指针记录的函数名以及位置变量记录的行数,定位内存泄露位置。

进一步地,所述第一定位模块6包括:

第一获取单元61,用于根据所述一内存块的字符串指针记录的函数名以及位置变量记录的行数,获取申请所述一内存块的第一代码位置;

第二获取单元62,用于根据gdb或backtrace函数获取函数栈信息;

第三获取单元63,用于根据所述函数栈信息,获取释放所述一内存块的第二代码位置;

第一定位单元64,用于根据所述第一代码位置和第二代码位置,定位内存越界的位置。

进一步地,所述第二定位模块8包括:

第四获取单元81,用于获取分配标记为第二字符的内存块的字符串指针记录的函数名以及位置变量记录的行数;

第五获取单元82,用于获取所述函数名和行数中出现次数最多的函数名和行数;

第二定位单元83,用于根据所获取的函数名和行数,定位内存泄露位置。

进一步地,还包括:

定义模块9,用于定义两组以上不同大小的内存块,其中,同一组内的各内存块的大小一致;

放入模块10,用于将同一组的内存块按照预设的顺序放入同一内存池,并将所述内存池的链表头指针指向最后放入的内存块,将所述内存池的链表尾指针指向最先放入的内存块;

连接模块11,用于将各内存池的链表头指针和链表尾指针通过数组进行连接;

申请模块12,用于申请内存时,选择内存块大小与所申请的内存大小最接近的内存池;

分配模块13,用于内存块分配时,将所述内存池中的第一个内存块作为被分配的内存块从链表中删除,将所述内存池中的第二个内存块的next指针指向空,将链表尾指针指向所述第二个内存块;

第一指向模块14,用于将被分配的内存块的next指针指向链表头;

确定模块15,用于内存块释放时,根据其所指向的链表头,确定对应的内存池;

第二指向模块16,用于将被释放的内存块的next指针指向对应的内存池中的最后一个内存块,并将所述内存池的链表头指针指向所述内存块。

综上所述,本发明提供的一种基于lte协议栈的内存池问题定位方法及其系统,通过在内存块中加入记录该内存中分配状态的分配标记,以及记录申请该内存块的函数名和函数位置的字符串指针和位置变量,即可在内存泄露,即内存池中超过预设个数的内存块都处于分配状态时,快速地定位出内存泄露的位置;同时,在内存块的头尾分别加入第一标记和第二标记,可在内存块释放时,通过检测第一标记和第二标记来判断该内存块是否发生越界,定位到发生越界的内存块,再根据该内存块所记录的函数名和函数位置,定位到内存越界的具体位置;本发明可在满足lte严格时序要求,不影响协议栈正常工作的情况下(每毫秒增加耗时1微妙以内,即影响在千分之1以内)解决内存池的内存泄露及内存越界问题。

以上所述仅为本发明的实施例,并非因此限制本发明的专利范围,凡是利用本发明说明书及附图内容所作的等同变换,或直接或间接运用在相关的技术领域,均同理包括在本发明的专利保护范围内。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1