一种基于Linux内核内存泄露的检测方法与流程

文档序号:13890368阅读:1180来源:国知局

本发明涉及通信技术领域,尤其涉及一种基于linux内核内存泄露的检测方法。



背景技术:

内存泄漏(memoryleak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。现有的在linux系统中,对内存进行泄露检测具体是通过kernel默认的memleak检测技术,当执行memleak检测方法之后,kernel(内核)会在调用kmalloc、vmalloc、kmem_cache_alloc等函数的返回处跟踪其指针,连同其大小和堆栈跟踪信息,一并存储到prio搜索树中,当内核释放内存的时候,会通过kmemleak_free删除存储的跟踪信息。kernel会启动一个kmemleak_s的内核线程,周期性的扫描已经存储的对象信息,然后判断对象是否被引用进而确定是否存在内存泄漏。上述的memleak技术存在以下缺陷,在检测过程中需要周期性的扫描,会增加cpu消耗负担;在内存分配、释放的时候再次进行slab分配以记录内存对象的信息,这样会延长内存分配、释放的时间,降低系统效率。



技术实现要素:

针对现有技术中检测内存泄露存在的上述问题,现提供一种旨在占用内存较小且不影响内存分配以及释放效率的基于linux内核内存泄露的检测方法。

具体技术方案如下:

一种基于linux内核内存泄露的检测方法,应用于内存泄露的检测,所述内存包括多个内存页,其中,创建一节点,通过所述节点统计每个所述内存页被调用的分配函数的返回地址,以及每个所述分配函数分配的所述内存页的数量;

包括以下步骤:

步骤s1、读取所述节点,获取每一个所述内存页所述分配函数的返回地址,以及所述分配分配函数对应分配的所述内存页的数量;

步骤s2、于读取完成之后,释放所述节点统计的所述分配函数的返回地址以及所述分配函数对应分配的所述内存页的数量;

步骤s3、再次读取所述节点,获取每一个所述分配函数的返回地址,以及所述分配函数对应分配的所述内存页的数量;

步骤s4、获取所述步骤s3中与所述步骤s1中同一所述分配函数各自所对应分配的所述内存页的数量,并进行比较取得差值;

在所述差值为正值且所述差值一直增大时,判断所述分配函数对应分配的内存页存在泄漏。

优选的,每个所述内存页包括一数据结构,于所述数据结构中增加一地址返回标识,一分配阶数以及一内存类型的分配标识;

所述地址返回标识用以记录内存分配时调用函数的地址;

所述分配标识用以表示所述内存页被分配的内存类型。

优选的,在每次内存分配时保存调用函数信息时,通过内核栈检查函数调用链,所述调用链中依次保存有公共分配函数以及所述分配函数所对应的返回地址、分配参数以及分配阶数;

获取所述调用链中顶层的所述分配函数所对应的所述返回地址、所述分配参数以及所述分配阶数;

并将所述返回地址保存至所述地址返回标识中以及将所述分配参数以及所述分配阶数保存至所述内存页面数据结构中。

优选的,所述内存中包括多个内存区,每个所述内存区由多个所述内存页形成,获取每个所述内存页的所述分配函数的方法,包括以下步骤:

步骤a1、按序读取每个所述内存区;

步骤a2、读取每个所述内存区中每个所述内存页所对应的所述数据结构,以获取每个所述内存页对应的所述分配函数对应的返回地址;

步骤a3、在所有所述内存区以及每个内存区中的所述内存页读取完成后,将获取的所有所述分配函数对应的返回地址,以及每个所述分配函数分配的所述内存页的数量形成一临时数组。

优选的,提供一打印模块,通过所述打印模块将所述临时数组中保存的每个所述分配函数、所述分配函数对应的返回地址以及所述分配函数对应分配的所述内存页的数量打印显示于一界面中。

优选的,在所述步骤a2中,提供一临时记录数组,用以保存读取的所述内存页对应的所述分配函数的返回地址;

在所述步骤a2中,还包括以下步骤:

步骤a21、判断所有的内存页是否读取完成;

若是,表示所有的所述内存页读取完成,退出;

步骤a22、读取下一所述内存页时将读取的分配函数对应的返回地址与所述临时记录数组中的返回地址进行匹配;

步骤a23、若匹配相同,则对当前的所述分配函数分配的内存页的数量加1,并返回步骤a21;

步骤a24、若匹配不同,则将所述内存页对应的所述分配函数的返回地址保存于所述临时记录数组中,并返回步骤a21。

优选的,当所述内存页被释放时,将保存在所述地址返回标识中的返回地址以及保存在所述数据结构中的所述分配参数以及所述分配阶数清空。

优选的,提供一宏配置模块用以配置形成所述地址返回标识。

上述技术方案具有如下优点或有益效果:在检测内存是否存在泄露的过程中对内存的消耗较小且不影响不影响内存分配以及释放效率,克服了现有技术中通过kernel默认的memleak检测技术在执行检测过程中需要周期性的扫描,增加cpu消耗负担以及在内存分配、释放的时候再次进行slab分配以记录内存对象的信息,会延长内存分配、释放的时间,降低系统效率的问题。

附图说明

参考所附附图,以更加充分的描述本发明的实施例。然而,所附附图仅用于说明和阐述,并不构成对本发明范围的限制。

图1为本发明一种基于linux内核内存泄露的检测方法的实施例的流程图;

图2为本发明一种基于linux内核内存泄露的检测方法的实施例中,关于获取每个所述内存页的所述分配函数的方法的流程图;

图3为本发明一种基于linux内核内存泄露的检测方法的实施例中,关于获取每个所述内存页的所述分配函数的方法的流程图;

图4为本发明一种基于linux内核内存泄露的检测方法的实施例中,关于内核内存分配api调用关系图。

具体实施方式

下面将结合本发明实施例中的附图,对本发明实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例仅仅是本发明一部分实施例,而不是全部的实施例。基于本发明中的实施例,本领域普通技术人员在没有作出创造性劳动的前提下所获得的所有其他实施例,都属于本发明保护的范围。

需要说明的是,在不冲突的情况下,本发明中的实施例及实施例中的特征可以相互组合。

下面结合附图和具体实施例对本发明作进一步说明,但不作为本发明的限定。

本发明的技术方案中包括一种基于linux内核内存泄露的检测方法。

一种基于linux内核内存泄露的检测方法的实施例,应用于内存泄露的检测,内存包括多个内存页,其中,创建一节点,通过节点统计每个内存页被调用的分配函数的返回地址,以及每个分配函数分配的内存页的数量;

如图1所示,包括以下步骤:

步骤s1、读取节点,获取每一个内存页分配函数的返回地址,以及分配分配函数对应分配的内存页的数量;

步骤s2、于读取完成之后,释放节点统计的分配函数的返回地址以及分配函数对应分配的内存页的数量;

步骤s3、再次读取节点,获取每一个分配函数的返回地址,以及分配函数对应分配的内存页的数量;

步骤s4、获取步骤s3中与步骤s1中同一分配函数各自所对应分配的内存页的数量,并进行比较取得差值;

在差值为正值且差值一直增大时,判断分配函数对应分配的内存页存在泄漏。

针对现有的在linux系统中,通过kernel默认的memleak检测技术对内存进行泄露检测,通常在检测过程中需要周期性的扫描,会增加cpu消耗负担;在内存分配、释放的时候再次进行slab分配以记录内存对象的信息,这样会延长内存分配、释放的时间,降低系统效率,如果内核分配的对象比较多的时候,kmemcache的slab会消耗掉很多内存;

举例说明典型的2gb的android平台,如果打开kmemleak配置,boot启动之后kmemleak的slab会消耗82mb左右的内存,这显然是一个极大的浪费。

本发明中,通过创建的节点在获取每个内存页对应的分配函数的返回地址,以及分配函数对应分配的内存页的数量,假设获取的分配函数为a1、a2、a3以及a4;函数a1、a2、a3、a4所对应的内存页的分配数量分别为100、200、300、400;

在对统计的分配函数的返回地址以及分配函数对应分配的内存页数量释放之后,再次读取访问节点,将再次统计获得的分配函数以及分配函数对应的内存页的分配数量,假设获取的函数为a1、a2、a3以及a4;

函数a1、a2、a3、a4所对应的内存页的分配数量分别为300、400、500、600;

通过将再次获取的分配函数a1与上一次获取的分配函数a1进行比较获得差值,当差值大于零,且差值一直增大则表示当前的分配函数对应分配的内存页存在泄漏;

若持平,或者差值小于零,且一直处于较小的状态,则表示当前分配函数对应分配的内存页正常。

在一种较优的实施方式中,如图4所示,每个内存页包括一数据结构,于数据结构中增加一地址返回标识用_ret_ip表示,一分配阶数标志以及一内存类型的分配标识用alloc_mask表示;

所述地址返回标识用以记录内存分配时调用函数的地址,这个调用函数名称即可用来确认内存分配者的身份信息;

分配标识用以表示内存页被分配的内存类型。

上述技术方案中,每个内存页的数据结构即(structpag结构)中增加的地址返回标识以及内存类型的分配标识,只增加一个long和int型成员,在64bit(位)体系中即增加了12个字节,对于具体的在2gb内存系统上,总体只增加了6mb的内存。相对于kmemleak增加的82mb的slab数据来说,大大减少了内存消耗。

在一种较优的实施方式中,在每次内存分配时保存调用函数信息时,通过内核栈检查函数调用链,调用链中依次保存有公共分配函数以及分配函数所对应的返回地址、分配参数以及分配阶数;

获取调用链中顶层的分配函数所对应的返回地址、分配参数以及分配阶数;

并将返回地址保存至地址返回标识中以及将分配参数以及分配阶数保存至内存页的数据结构中。

上述技术方案中,分配阶数包括每个分配函数所要分配的内存页的数量,通常用2k表示,每个内存页的大小为4kb,分配参数中包括当前分配参数分配的内存的类型。

在一种较优的实施方式中,内存中包括多个内存区,每个内存区由多个内存页形成,获取每个内存页的分配函数的方法,如图2所示,包括以下步骤:

步骤a1、按序读取每个内存区;

步骤a2、读取每个内存区中每个内存页所对应的数据结构,以获取每个内存页对应的分配函数对应的返回地址;

步骤a3、在所有内存区以及每个内存区中的内存页读取完成后,将获取的所有分配函数对应的返回地址,以及每个分配函数分配的内存页的数量形成一临时数组。

在一种较优的实施方式中,提供一打印模块,通过打印模块将临时数组中保存的每个分配函数、分配函数对应的返回地址以及分配函数对应分配的内存页的数量打印显示于一界面中。

在一种较优的实施方式中,提供一临时记录数组,用以保存读取的内存页对应的分配函数的返回地址;

如图3所示,在步骤a2中,还包括以下步骤:

步骤a21、判断当前的内存区中的所有的内存页是否读取完成;

若是,表示所有的内存页读取完成,退出;

步骤a22、读取下一内存页时将读取的分配函数对应的返回地址与临时记录数组中的返回地址进行匹配;

步骤a23、若匹配相同,则对当前的分配函数分配的内存页的数量加1,并返回步骤a21;

步骤a24、若匹配不同,则将内存页对应的分配函数的返回地址保存于临时记录数组中,并返回步骤a21。

上述技术方案中,每个内存区用zone表示,zone中保存有多个内存页,每个内存页中包括structpag结构,在读取内存区时,首先从zone的start_pfn到end_pfn,根据pfn获得内存页的structpage结构,然后从structpage结构中找出_ret_ip(分配函数对应的返回地址),并根据_ret_ip在一个临时记录ret_ip的数组中查找,如果没有匹配项,则这是一个新的_ret_ip,记录它并根据这个page的分配order(阶数)增加它的分配次数,如此顺序循环完所有的page和所有的zone。

可以得到一个记录所有分配者的返回地址的_ret_ip以及总计分配次数的临时数组;最后将其打印出来,完成对节点(/proc/pagetrace)的读取功能。

在一种较优的实施方式中,当内存页被释放时,将保存在地址返回标识中的返回地址以及保存在分配标识中的分配参数以及分配阶数清空。

上述技术方案中,当对分配函数分配的内存进行释放时,若内存页中保存在地址返回标识中的返回地址,以及保存在分配标识中的分配参数以及分配阶数被清空后,则表示当前的内存页释放完成,没有被分配函数所调用。

在一种较优的实施方式中,提供一宏配置模块用以配置形成地址返回标识。

上述技术方案中,linux环境下,可通过宏配置模块即宏_ret_ip_获得编译器支持的函数的返回地址,即得到__alloc_pages_nodemask函数的调用者。

以上所述仅为本发明较佳的实施例,并非因此限制本发明的实施方式及保护范围,对于本领域技术人员而言,应当能够意识到凡运用本发明说明书及图示内容所作出的等同替换和显而易见的变化所得到的方案,均应当包含在本发明的保护范围内。

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