一种内存故障检测方法及装置与流程

文档序号:19155040发布日期:2019-11-16 00:38阅读:180来源:国知局
一种内存故障检测方法及装置与流程

本发明实施例涉及计算机技术领域,具体涉及一种内存故障检测方法及装置。



背景技术:

内存改写、内存泄漏和死锁是代码开发过程中的常见问题,内存改写主要分为3种情形:内存越界、访问已释放内存和指针异常。内存泄漏是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费。死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。

目前内存故障检测工具主要为valgrind,valgrind中用于内存检测的工具为memcheck。对于内存改写,memcheck维护两个全局表valid-value和valid-address。valid-value对于整个地址空间的每一个字节,都有与之对应的8个bit,cpu的每个寄存器也有对应的bit向量,该表负责记录字节或者寄存器是否具有有效的、已经初始化的值;valid-address对于进程整个地址空间中的每一个字节,都有与之对应的1个bit负责记录该地址能否被读写。当进行内存读写操作时会从valid-value和valid-address这两个全局表取值,判断地址是否可读写或者是否初始化。对于内存泄漏,memcheck判断是否存在指向分配地址的指针,若只存在指向分配内存的指针但不是首地址则认为是可能泄漏,如果没有指针指向已分配内存则认为直接泄漏。对于多线程锁的检查则是另外一个工具helgrind,通过记录加锁、解锁的线程和位置,当发生死锁时,中断程序后则会输出占用锁的线程。

valgrind对于内存改写和内存泄漏都有比较好的支持,但工具内存损耗和性能都较为严重,当一个应用由多个模块组成时,valgrind无法进一步定位出现问题的模块。



技术实现要素:

针对现有技术中的缺陷,本发明实施例提供了一种内存故障检测方法及装置。

第一方面,本发明实施例提供一种内存故障检测方法,包括:

预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息;

建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息;

在计算机程序编译过程中,在内存访问的指令中增加检测代码,所述检测代码用于获取当前访问的内存信息;

遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障;

若出现内存故障,则根据所述红黑树节点中保存的申请者信息确定出现内存故障的申请模块。

如上述方法,可选地,所述预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息,包括:

预先编译各个模块的内存分配函数的重构函数,所述重构函数用于在分配内存时多申请预设字节的隔离带以隔离不同的内存分配,并获取当前分配的内存首地址、内存大小和申请分配内存的模块信息;

相应地,所述建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息,包括:

建立内存改写检测红黑树,在计算机程序编译过程中,当有内存分配时,将计算机程序链接至内存分配函数对应的重构函数,在所述内存改写检测红黑树中增加当前内存分配对应的节点,获取当前内存分配的内存首地址、内存大小和申请分配内存的模块信息,并在所述节点中保存所述内存首地址、内存大小和申请分配内存的模块信息。

如上述方法,可选地,所述遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障,包括:

遍历所述内存改写检测红黑树节点,对比访问的内存信息和所述内存改写检测红黑树节点中保存的内存首地址、内存大小;

若所述访问的内存信息不在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为访问未知内存;

若所述访问的内存信息中只有部分内存信息在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为内存越界。

如上述方法,可选地,所述在计算机程序编译过程中,当有内存操作时,在所述红黑树中增加当前内存操作对应的节点之前,还包括:

在计算机程序编译过程中,在首次分配内存时创建扫描线程;

相应地,所述建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息,包括:

建立内存泄露检测红黑树,在计算机程序编译过程中,当有动态分配内存时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前动态分配内存对应的节点,获取当前动态分配内存的内存信息和申请模块信息,并在所述节点中保存所述内存信息和申请模块信息;

相应地,所述遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障,包括:

按预设周期定时扫描计算机程序编译过程中动态分配的内存,判断所述内存泄露检测红黑树中是否存在被扫描的内存指针,若不存在,则确定内存故障为内存泄露。

如上述方法,可选地,还包括:

通过所述检测代码检测到访问了所述内存泄露检测红黑树中记载的动态内存时,记录并更新最近访问时刻;

若待检测动态内存的最近访问时刻与当前时刻的差值超过预设时间段阈值,则确定所述待检测动态内存发生了内存泄露故障。

如上述方法,可选地,所述预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息,包括:

预先分别编译线程操作函数的重构函数和锁操作函数的重构函数,所述线程操作函数的重构函数用于获取线程信息和线程标识,所述锁操作函数的重构函数用于获取锁信息和锁标识;

相应地,所述建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息,包括:

建立死锁检测红黑树,在计算机程序编译过程中,当建立线程时,将计算机程序链接至所述线程操作函数的重构函数,在所述红黑树中增加当前建立线程对应的节点,获取当前线程,并在所述节点中保存所述线程信息和当前线程的线程标识;

在计算机程序编译过程中,当有加锁操作时,将计算机程序链接至所述锁操作函数的重构函数,在所述死锁检测红黑树中所述锁操作所在线程对应的节点中增加子节点,获取当前锁信息,并在所述子节点中按获取顺序依次保存所述锁信息和对应的锁标识,并标记锁状态为持有状态;

当有解锁操作时,在所述红黑树中对应的线程中查找与解锁操作对应的子节点,清除所述与解锁操作对应的子节点中锁信息的持有状态。

如上述方法,可选地,还包括:

遍历所述死锁检测红黑树中的所有子节点,依次获取第i个线程中第j个锁uij在第m个线程中的位置pijm以及所述锁uij在所述第i个线程中的位置piji;

获取所述第m个线程中第k个锁umk在所述第i个线程中的位置pmki以及所述锁umk在所述第m个线程中的位置pmkm,其中i,j,k,m为整数,且i,m∈[0,n-1],n为所述死锁检测红黑树中记载的线程总数;

若判断获知sign(i,m)的结果为非负数,则确定所述第i个线程和所述第m个线程没有发生死锁,其中sign(i,m)={(piji-pmki)*(pijm-pmkm)}。

如上述方法,可选地,还包括:

若发生死锁,则通过所述死锁检测红黑树获取引起第一线程阻塞的第一锁,并在所述死锁检测红黑树中将所述第一锁对应的子节点标记为扫描状态,并记录标记次数;

通过所述死锁检测红黑树查找到持有所述第一锁的所有线程,判断每个持有所述第一锁的线程中引起阻塞的其他锁,并在所述死锁检测红黑树中将所述其他锁对应的子节点标记为扫描状态并记录标记次数,直到所述死锁检测红黑树中所有的子节点均被标记为扫描状态;

若第二锁的标记次数大于预设次数阈值,则将持有所述第二锁的所有线程中的每个锁标记为死锁状态。

第二方面,本发明实施例提供一种内存故障检测装置,包括:

预编译模块,用于预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息;

红黑树模块,用于建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息;

获取模块,用于在计算机程序编译过程中,在内存访问的指令中增加检测代码,所述检测代码用于获取当前访问的内存信息;

检测模块,用于遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障;

定位模块,用于若出现内存故障,则根据所述红黑树节点中保存的申请者信息确定出现内存故障的申请模块。

如上述装置,可选地,所述预编译模块具体用于:

预先编译各个模块的内存分配函数的重构函数,所述重构函数用于在分配内存时多申请预设字节的隔离带以隔离不同的内存分配,并获取当前分配的内存首地址、内存大小和申请分配内存的模块信息;

相应地,所述红黑树模块具体用于:

建立内存改写检测红黑树,在计算机程序编译过程中,当有内存分配时,将计算机程序链接至内存分配函数对应的重构函数,在所述内存改写检测红黑树中增加当前内存分配对应的节点,获取当前内存分配的内存首地址、内存大小和申请分配内存的模块信息,并在所述节点中保存所述内存首地址、内存大小和申请分配内存的模块信息。

如上述装置,可选地,所述检测模块具体用于:

遍历所述内存改写检测红黑树节点,对比访问的内存信息和所述内存改写检测红黑树节点中保存的内存首地址、内存大小;

若所述访问的内存信息不在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为访问未知内存;

若所述访问的内存信息中只有部分内存信息在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为内存越界。

如上述装置,可选地,还包括:

创建模块,用于在计算机程序编译过程中,在首次分配内存时创建扫描线程;

相应地,所述红黑树模块具体用于:

建立内存泄露检测红黑树,在计算机程序编译过程中,当有动态分配内存时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前动态分配内存对应的节点,获取当前动态分配内存的内存信息和申请模块信息,并在所述节点中保存所述内存信息和申请模块信息;

相应地,所述检测模块具体用于:

按预设周期定时扫描计算机程序编译过程中动态分配的内存,判断所述内存泄露检测红黑树中是否存在被扫描的内存指针,若不存在,则确定内存故障为内存泄露。

如上述装置,可选地,还包括:

统计模块,用于通过所述检测代码检测到访问了所述内存泄露检测红黑树中记载的动态内存时,记录并更新最近访问时刻;

相应地,所述定位模块还用于若待检测动态内存的最近访问时刻与当前时刻的差值超过预设时间段阈值,则确定所述待检测动态内存发生了内存泄露故障。

如上述装置,可选地,所述预编译模块具体用于:

预先分别编译线程操作函数的重构函数和锁操作函数的重构函数,所述线程操作函数的重构函数用于获取线程信息和线程标识,所述锁操作函数的重构函数用于获取锁信息和锁标识;

相应地,所述红黑树模块具体用于:

建立死锁检测红黑树,在计算机程序编译过程中,当建立线程时,将计算机程序链接至所述线程操作函数的重构函数,在所述红黑树中增加当前建立线程对应的节点,获取当前线程,并在所述节点中保存所述线程信息和当前线程的线程标识;

在计算机程序编译过程中,当有加锁操作时,将计算机程序链接至所述锁操作函数的重构函数,在所述死锁红黑树中所述锁操作所在线程对应的节点中增加子节点,获取当前锁信息,并在所述子节点中按获取顺序依次保存所述锁信息和对应的锁标识,并标记锁状态为持有状态;

当有解锁操作时,在所述红黑树中对应的线程中查找与解锁操作对应的子节点,清除所述与解锁操作对应的子节点中锁信息的持有状态。

如上述装置,可选地,还包括:

第一锁位置确定模块,用于遍历所述死锁检测红黑树中的所有子节点,依次获取第i个线程中第j个锁uij在第m个线程中的位置pijm以及所述锁uij在所述第i个线程中的位置piji;

第二锁位置确定模块,用于获取,以及所述第m个线程中第k个锁umk在所述第i个线程中的位置pmki以及所述锁umk在所述第m个线程中的位置pmkm,其中i,j,k,m为整数,且i,m∈[0,n-1],n为所述死锁检测红黑树中记载的线程总数;

计算模块,用于若判断获知sign(i,m)的结果为非负数,则确定所述第i个线程和所述第m个线程没有发生死锁,其中sign(i,m)={(piji-pmki)*(pijm-pmkm)}。

如上述装置,可选地,还包括:

标记模块,用于若发生死锁,则通过所述死锁检测红黑树获取引起第一线程阻塞的第一锁,并在所述死锁检测红黑树中将所述第一锁对应的子节点标记为扫描状态,并记录标记次数;

扫描模块,用于通过所述死锁检测红黑树查找到持有所述第一锁的所有线程,判断每个持有所述第一锁的线程中引起阻塞的其他锁,并在所述死锁检测红黑树中将所述其他锁对应的子节点标记为扫描状态并记录标记次数,直到所述死锁检测红黑树中所有的子节点均被标记为扫描状态;

相应地,所述定位模块用于若第二锁的标记次数大于预设次数阈值,则将所述持有第二锁的所有线程中的每个锁标记为死锁状态。

本发明实施例提供的内存故障检测方法,在编译过程中链接重构函数获取红黑树需要记载的内存信息和申请内存的模块信息,通过在程序中插入检测代码获取分配的内存信息,支持在线的内存故障检测,引入申请者信息,能够快速定位出现故障的模块,且该内存故障检测方法内存使用少,性能损耗小,有利于在内存资源受限的环境中使用。

附图说明

为了更清楚地说明本发明实施例或现有技术中的技术方案,下面将对实施例或现有技术描述中所需要使用的附图作一简单地介绍,显而易见地,下面描述中的附图是本发明的一些实施例,对于本领域普通技术人员来讲,在不付出创造性劳动的前提下,还可以根据这些附图获得其他的附图。

图1为本发明实施例提供的内存故障检测方法流程示意图;

图2为本发明实施例提供的内存故障检测装置的结构示意图。

具体实施方式

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

图1为本发明实施例提供的内存故障检测方法流程示意图,如图1所示,该方法包括:

步骤s11、预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息;

具体地,在进行内存故障检测时,首先编译各个内存操作函数的重构函数,内存操作函数包括但不限于:malloc、free等各类内存分配函数,pthread_create、mutex等各类线程操作函数以及spin、rwlock等各类锁操作函数。重构函数与原函数功能类似,重构函数用于获取内存操作的内存信息和申请内存操作的模块信息。例如用_wrap_func代替func函数,如使用_wrap_malloc代替malloc函数,或者在代码编写时直接使用带block名的重构函数代替原有函数,以此完成malloc、free、pthread_create、mutex、spin、rwlock等各类内存操作函数的重构,在重构函数中实现对内存信息、线程信息和锁信息的采集。

步骤s12、建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息;

具体地,在建立内存故障检测红黑树并存储在内存中,在计算机程序编译过程中,当有内存操作(例如分配内存、创建线程等)时,将计算机程序链接至内存操作函数对应的重构函数,例如当程序执行至malloc函数入口时,将程序链接至提前编译好的重构函数_wrap_malloc,_wrap_malloc函数可以在内存故障检测红黑树中创建节点object,在object中保存获取的malloc函数分配的内存信息以及申请内存分配的模块信息,或者在节点object下建立子节点block,block保存申请者信息,这样内存故障检测红黑树中每个object中元素block表示是哪个模块申请或创建了对应的object。

步骤s13、在计算机程序编译过程中,在内存访问的指令中增加检测代码,所述检测代码用于获取当前访问的内存信息;

具体地,在计算机程序编译过程中,对可重定位文件elf进行修改,修改的内容为在内存访问的指令中增加一段检测代码,在访问内存前插入检测代码,以获取当前访问的内存信息,通过在代码中插入检测代码,无需编译器支持,适用于各种代码检测。

步骤s14、遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障;

具体地,获取到当前访问的内存信息之后,对比访问的内存信息和内存故障检测红黑树节点object中保存的内存信息,由于object保存的是分配的内存信息,如果当前访问的内存信息不存在于object保存的内存信息中,则表示出现了内存故障。

步骤s15、若出现内存故障,则根据所述红黑树节点中保存的申请者信息确定出现内存故障的申请模块。

具体地,如果检测到出现了内存故障,且已知出现内存故障的节点object,则可以根据object中记载的申请者信息,确定出现内存故障的申请模块,

本发明实施例提供的内存故障检测方法,在编译过程中链接重构函数获取红黑树需要记载的内存信息和申请内存的模块信息,通过在程序中插入检测代码获取分配的内存信息,支持在线的内存故障检测,引入申请者信息,能够快速定位出现故障的模块,且该内存故障检测方法内存使用少,性能损耗小,有利于在内存资源受限的环境中使用。

在上述实施例的基础上,进一步地,所述预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息,包括:

预先编译各个模块的内存分配函数的重构函数,所述重构函数用于在分配内存时多申请预设字节的隔离带以隔离不同的内存分配,并获取当前分配的内存首地址、内存大小和申请分配内存的模块信息;

相应地,所述建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息,包括:

建立内存改写检测红黑树,在计算机程序编译过程中,当有内存分配时,将计算机程序链接至内存分配函数对应的重构函数,在所述内存改写检测红黑树中增加当前内存分配对应的节点,获取当前内存分配的内存首地址、内存大小和申请分配内存的模块信息,并在所述节点中保存所述内存首地址、内存大小和申请分配内存的模块信息。

具体地,当进行内存改写检测时,首先针对各个模块的内存分配函数,分别编译与之对应的重构函数,利用上述的_wrap_func形式的链接选项,实现memset、memcpy、memmove、strcpy、strcat等内存操作函数的重构,这些重构函数用于在申请内存时,多分配预设字节的隔离带,例如会多申请一个8字节的空间,记为redzone,作为每次申请的内存之间的隔离。重构函数可以获得对应内存分配函数当前分配的内存信息和申请分配内存的模块信息,内存信息包括分配的内存的首地址和分配的内存大小。由于可以为每个模块分别编译其对应的重构函数,因此通过链接不同的重构函数,就可以确定申请分配内存的模块信息。

之后,建立内存改写检测红黑树,内存改写检测红黑树中存储每次内存分配的申请模块和分配的内存信息,具体地,在计算机程序编译过程中,当有内存分配时,链接至内存分配函数对应的重构函数,重构函数在内存改写检测红黑树中增加当前内存分配的节点,记录分配的内存地址和内存大小,并记录申请分配内存的模块信息,以此来获取计算机程序编译过程中的全局变量、栈空间或者动态分配的内存信息。

在上述各实施例的基础上,进一步地,所述遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障,包括:

遍历所述内存改写检测红黑树节点,对比访问的内存信息和所述内存改写检测红黑树节点中保存的内存首地址、内存大小;

若所述访问的内存信息不在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为访问未知内存;

若所述访问的内存信息中只有部分内存信息在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为内存越界。

具体地,建立完成内存改写检测红黑树之后,当检测代码检测到有内存访问时,遍历内存改写检测红黑树中的所有节点,对比访问的内存信息和内存改写检测红黑树中保存的内存首地址和内存大小信息,如果当前访问的内存信息不在内存改写检测红黑树节点记载的所有内存信息中,则表明当前访问了未知内存,标记出现了内存故障。进一步地,可对当前访问内存的模块进行追踪,以确定出现内存故障的模块。

如果访问的内存信息中只有一部分内存信息在内存改写检测红黑树节点记载的内存信息中,另一部分不在记载的内存信息中,则表明出现了内存越界,进一步,可根据记载在内存改写检测红黑树节点中的申请模块信息,确定出现内存故障的模块。

如果访问的内存信息在内存改写检测红黑树节点记载的内存信息中,则表明没有出现内存改写故障。

本发明实施例提供的内存故障检测方法,通过在内存分配时维护内存改写检测红黑树,记录分配的内存信息和申请分配内存的模块信息,通过插入检测代码获取访问的内存信息,对比访问的内存信息和记载的分配的内存信息,根据对比结果判断是否存在内存改写故障,支持在线的内存故障检测,引入申请者信息,能够快速定位出现故障的模块,且该内存故障检测方法内存使用少,性能损耗小,有利于在内存资源受限的环境中使用。

在上述各实施例的基础上,进一步地,所述在计算机程序编译过程中,当有内存操作时,在所述红黑树中增加当前内存操作对应的节点之前,还包括:

在计算机程序编译过程中,在首次分配内存时创建扫描线程;

相应地,所述建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息,包括:

建立内存泄露检测红黑树,在计算机程序编译过程中,当有动态分配内存时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前动态分配内存对应的节点,获取当前动态分配内存的内存信息和申请模块信息,并在所述节点中保存所述内存信息和申请模块信息;

相应地,所述遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障,包括:

按预设周期定时扫描计算机程序编译过程中动态分配的内存,判断所述内存泄露检测红黑树中是否存在被扫描的内存指针,若不存在,则确定内存故障为内存泄露。

具体地,当进行内存泄露检测时,在首次分配内存时创建扫描线程,之后建立内存泄露检测红黑树,在计算机程序编译过程中,当有动态分配内存时,将计算机程序链接至内存操作函数对应的重构函数,利用重构函数在红黑树中增加当前动态分配内存对应的节点,获取当前动态分配内存的内存信息和申请模块信息,并在节点中保存所述内存信息和申请模块信息。按预设周期定时扫描内存泄露检测红黑树中记载的动态分配内存,判断内存泄露检测红黑树中是否存在被扫描的内存指针,若不存在,则表明发生了内存泄露。

在上述各实施例的基础上,进一步地,还包括:

通过所述检测代码检测到访问了所述内存泄露检测红黑树中记载的动态内存时,记录并更新最近访问时刻;

若待检测动态内存的最近访问时刻与当前时刻的差值超过预设时间段阈值,则确定所述待检测动态内存发生了内存泄露故障。

具体地,还可以通过另一种方法判断是否发生了内存泄露,当通过检测代码检测到访问了内存泄露检测红黑树中记载的动态内存时,在红黑树中记录当前的访问时刻,如果再次访问该动态内存,则更新最近访问时刻。之后对所有动态内存的最近访问时刻进行排序,若待检测动态内存的最近访问时刻与当前时刻的差值超过预设时间段阈值,即该动态内存很久没有被访问了,则确定待检测动态内存发生了内存泄露故障。

本发明实施例提供的内存故障检测方法,通过在动态内存分配时维护内存泄露检测红黑树,记录动态分配的内存信息和申请分配内存的模块信息,通过插入检测代码获取访问的内存信息,对比访问的内存信息的最近访问时刻,根据时间长短判断是否存在内存泄露故障,支持在线的内存故障检测,能够检测出比较隐蔽的内存泄漏问题。

在上述各实施例的基础上,进一步地,所述预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息,包括:

预先分别编译线程操作函数的重构函数和锁操作函数的重构函数,所述线程操作函数的重构函数用于获取线程信息和线程标识,所述锁操作函数的重构函数用于获取锁信息和锁标识;

相应地,所述建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息,包括:

建立死锁检测红黑树,在计算机程序编译过程中,当建立线程时,将计算机程序链接至所述线程操作函数的重构函数,在所述红黑树中增加当前建立线程对应的节点,获取当前线程,并在所述节点中保存所述线程信息和当前线程的线程标识;

在计算机程序编译过程中,当有加锁操作时,将计算机程序链接至所述锁操作函数的重构函数,在所述死锁检测红黑树中所述锁操作所在线程对应的节点中增加子节点,获取当前锁信息,并在所述子节点中按获取顺序依次保存所述锁信息和对应的锁标识,并标记锁状态为持有状态;

当有解锁操作时,在所述红黑树中对应的线程中查找与解锁操作对应的子节点,清除所述与解锁操作对应的子节点中锁信息的持有状态。

具体地,当进行死锁检测时,预先编译线程操作函数的重构函数和锁操作函数的重构函数,锁包括互斥锁、自旋锁和读写锁等各类锁,线程操作函数的重构函数用于获取线程信息和线程标识,线程标识用于区分不同的线程,锁操作函数的重构函数用于获取锁信息和锁标识,锁标识用于区分不同的锁;

之后,建立死锁检测红黑树,在计算机程序编译过程中,当建立线程时,将计算机程序链接至线程操作函数的重构函数,利用重构函数在红黑树中增加当前线程操作对应的节点,获取当前线程和线程标识,并在节点中保存线程信息和线程标识,当某个线程中有加锁操作时,获取锁信息和锁标识,在死锁检测红黑树中按获取顺序增加该锁对应的子节点,保存锁信息和锁标识,并标记该锁的状态为持有状态,其中线程中锁的保存顺序为线程中锁的位置,即,某个线程中第一个获取的锁的位置为0,第二个获取的锁的位置为1等。

当某个线程中有解锁操作时,在死锁检测红黑树中该线程对应的节点查找到对应的持有锁,将锁标记的持有状态进行清除,这样在死锁检测红黑树中,被标记为持有状态的均为加锁操作且未被解锁的线程锁。由于将互斥锁、自旋锁和读写锁等类型进行抽象,抽象后的锁具有如下特性:一个线程被阻塞,最多只能被一个锁所阻塞;一个锁可以被多个线程持有,也可以被同一线程持有多次,但需要相应的解锁操作。通过将每个线程中的锁信息(包括加锁和解锁)保存在死锁检测红黑树中,根据抽象后的锁的特性,就可检测线程是否出现死锁,进一步还可以通过死锁检测红黑树确定发生死锁的所有线程。

本发明实施例提供的内存故障检测方法,通过在线程中获取到锁操作时维护死锁检测红黑树,记录每个线程的锁信息并标记锁状态,通过死锁检测红黑树判断是否出现死锁,支持在线的死锁检测,提高了死锁检测的正确率。

在上述各实施例的基础上,进一步地,还包括:

遍历所述死锁检测红黑树中的所有子节点,依次获取第i个线程中第j个锁uij在第m个线程中的位置pijm以及所述锁uij在所述第i个线程中的位置piji;

获取所述第m个线程中第k个锁umk在所述第i个线程中的位置pmki以及所述锁umk在所述第m个线程中的位置pmkm,其中i,j,k,m为整数,且i,m∈[0,n-1],n为所述死锁检测红黑树中记载的线程总数;

若判断获知sign(i,m)的结果为非负数,则确定所述第i个线程和所述第m个线程没有发生死锁,其中sign(i,m)={(piji-pmki)*(pijm-pmkm)}。

具体地,在死锁检测红黑树中,记录线程所有的持有锁信息,按照持有顺序进行排序。解锁时记录当前线程锁持有锁和锁顺序信息,同时标记所有的持有锁,解锁时取消对应锁的标记,当下一次解锁时发现所有的持有锁都为标记状态且所有顺序包含在之前的记录中,则不做记录,防止记录信息冗余。若死锁检测红黑树中共有n个线程,m个持有锁,则首先遍历死锁检测红黑树中的所有子节点,即遍历所有线程中的持有锁,依次获取第i个线程中第j个锁uij在该线程中的位置piji以及该锁uij在其他各个线程,例如第m个线程中的位置pijm,其中i为从0到n-1的整数,j为小于m-1的整数。之后依次获取其他n-1个线程中第k个锁在第i个线程中的位置,例如第m个线程中第k个锁umk在第i个线程中的位置pmki以及锁umk在第m个线程中的位置pmkm,其中k为小于m-1的整数,如果某个锁在某个线程中不存在或者该锁在两个线程的位置相同且均有持有锁,则跳过该锁,检测下一个锁。

计算sign(i,m)={(piji-pmki)*(pijm-pmkm)},若结果为0或正数,则表明第i个线程和第m个线程没有发生死锁,若结果为负数,则表明第i个线程和第m个线程可能发生死锁。例如,当计算结果为负时,若线程i或线程m先一次性把两个锁获取到了,则不会发生死锁。如果线程i先获取一个锁,线程m再获取另外一个锁,此时会出现循环依赖,发生死锁。该公式表明,对任意两个锁e和锁f,如果这两个锁在线程i的加锁前后顺序与在这两个锁在线程m的加锁前后顺序相同,则线程i与线程m不会发生死锁。

例如,死锁检测红黑树中有3个线程,线程0、线程1和线程2,线程0中的持有锁按顺序依次为锁a、锁b和锁c,线程1中的持有锁按顺序依次为锁c、锁b和锁a,线程2中的持有锁按顺序依次为锁c、锁a和锁b。

首先取线程0中的第一个锁锁a,锁a在线程0中的位置p000=0,锁a在线程1中的位置为p001=2,锁a在线程2中的位置为p002=1,线程1中的第一个锁锁c在线程0中的位置p100=2,线程1中的第一个锁锁c在线程1中的位置p101=0,线程2中的第一个锁锁c在线程0中的位置p200=2,线程2中的第一个锁锁c在线程2中的位置p202=0。

线程0和线程1的符号函数sign(0,1)={(p000-p100)*(p001-p101)}=(0-2)*(2-0),结果为负数,表明当线程0获取到锁a后发生调度,线程1获取到锁c,则会发生线程1无法继续获取锁c(被线程1持有),线程1无法继续获取锁a(被线程0持有),则线程0和线程1发生死锁。

线程0和线程2的符号函数sign(0,2)={(p000-p200)*(p002-p202)}=(0-2)*(1-0),结果为负数,则线程0和线程2可能发生死锁。

取线程1中的第一个锁锁c在线程2中的位置p102=0,线程1中的第一个锁锁c在线程1中的位置p101=0,线程2中的第一个锁锁c在线程1中的位置p201=0,线程2中的第一个锁锁c在线程2中的位置p202=0。

线程1和线程2的符号函数sign(1,2)={(p101-p201)*(p102-p202)}=(0-0)*(0-0),结果为0,表明线程1和线程2一次性获取到自己需要的锁,则线程1和线程2不会发生死锁。

在上述实施例的基础上,进一步地,还包括:

若发生死锁,则通过所述死锁检测红黑树获取引起第一线程阻塞的第一锁,并在所述死锁检测红黑树中将所述第一锁对应的子节点标记为扫描状态,并记录标记次数;

通过所述死锁检测红黑树查找到持有所述第一锁的所有线程,判断每个持有所述第一锁的线程中引起阻塞的其他锁,并在所述死锁检测红黑树中将所述其他锁对应的子节点标记为扫描状态并记录标记次数,直到所述死锁检测红黑树中所有的子节点均被标记为扫描状态;

若第二锁的标记次数大于预设次数阈值,则将持有所述第二锁的所有线程中的每个锁标记为死锁状态。

具体地,如果已经发生死锁,则需要标记是哪些锁为死锁状态。通过死锁检测红黑树获取引起第一线程阻塞的第一锁锁a,并在死锁检测红黑树中将锁a对应的子节点标记为扫描状态,并记录标记次数为1。然后通过死锁检测红黑树查找到所有持有锁a的线程,判断这些线程中引起该线程阻塞的其他锁,将这些其他锁标记为扫描状态,并记录标记次数为1,当第二次扫描到标记次数为1的锁时,更新标记次数为2,以此类推,直到死锁检测红黑树中所有的子节点均被标记为扫描状态,如果某个锁的标记次数大于预设次数阈值,例如标记次数大于1,则将持有该锁的所有线程中的每个锁都标记为死锁状态。

例如,获取引起线程1阻塞的锁b,并标记为已扫描,扫描次数为1,从死锁检测红黑树中找到持有锁b的所有线程(例如其中一个是线程2),获取引起线程2阻塞的锁c,并标记为已扫描,扫描次数根据实际情况更新。以此类推。当检测到某个锁被至少扫描两次时,则认为是出现了死锁,标记死锁的扫描路径上的所有锁为死锁状态。按照该方法继续检测其他线程。本发明实施例通过维护死锁检测红黑树,不仅可以判断是否出现死锁,还可以定位具体出现问题的锁信息,进一步提高了死锁检测效率。

图2为本发明实施例提供的内存故障检测装置的结构示意图,如图2所示,该装置包括:预编译模块21、红黑树模块22、获取模块23、检测模块24和定位模块25,其中:

预编译模块21用于预先编译内存操作函数的重构函数,所述重构函数用于获取内存操作的内存信息和申请者信息;红黑树模块22用于建立内存故障检测红黑树,在计算机程序编译过程中,当有内存操作时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前内存操作对应的节点,获取当前内存操作的内存信息和申请者信息,并在所述节点中保存所述内存信息和申请者信息;获取模块23用于在计算机程序编译过程中,在内存访问的指令中增加检测代码,所述检测代码用于获取当前访问的内存信息;检测模块24用于遍历红黑树节点,对比访问的内存信息和所述红黑树节点中保存的内存信息,根据对比结果确定是否出现内存故障;定位模块25用于若出现内存故障,则根据所述红黑树节点中保存的申请者信息确定出现内存故障的申请模块。

在上述实施例的基础上,进一步地,所述预编译模块具体用于:

预先编译各个模块的内存分配函数的重构函数,所述重构函数用于在分配内存时多申请预设字节的隔离带以隔离不同的内存分配,并获取当前分配的内存首地址、内存大小和申请分配内存的模块信息;

相应地,所述红黑树模块具体用于:

建立内存改写检测红黑树,在计算机程序编译过程中,当有内存分配时,将计算机程序链接至内存分配函数对应的重构函数,在所述内存改写检测红黑树中增加当前内存分配对应的节点,获取当前内存分配的内存首地址、内存大小和申请分配内存的模块信息,并在所述节点中保存所述内存首地址、内存大小和申请分配内存的模块信息。

在上述各实施例的基础上,进一步地,所述检测模块具体用于:

遍历所述内存改写检测红黑树节点,对比访问的内存信息和所述内存改写检测红黑树节点中保存的内存首地址、内存大小;

若所述访问的内存信息不在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为访问未知内存;

若所述访问的内存信息中只有部分内存信息在所述内存改写检测红黑树节点记载的内存信息中,则确定内存故障为内存越界。

在上述各实施例的基础上,进一步地,还包括:

创建模块,用于在计算机程序编译过程中,在首次分配内存时创建扫描线程;

相应地,所述红黑树模块具体用于:

建立内存泄露检测红黑树,在计算机程序编译过程中,当有动态分配内存时,将计算机程序链接至内存操作函数对应的重构函数,在所述红黑树中增加当前动态分配内存对应的节点,获取当前动态分配内存的内存信息和申请模块信息,并在所述节点中保存所述内存信息和申请模块信息;

相应地,所述检测模块具体用于:

按预设周期定时扫描计算机程序编译过程中动态分配的内存,判断所述内存泄露检测红黑树中是否存在被扫描的内存指针,若不存在,则确定内存故障为内存泄露。

在上述各实施例的基础上,进一步地,还包括:

统计模块,用于通过所述检测代码检测到访问了所述内存泄露检测红黑树中记载的动态内存时,记录并更新最近访问时刻;

相应地,所述定位模块还用于若待检测动态内存的最近访问时刻与当前时刻的差值超过预设时间段阈值,则确定所述待检测动态内存发生了内存泄露故障。

在上述各实施例的基础上,进一步地,所述预编译模块具体用于:

预先分别编译线程操作函数的重构函数和锁操作函数的重构函数,所述线程操作函数的重构函数用于获取线程信息和线程标识,所述锁操作函数的重构函数用于获取锁信息和锁标识;

相应地,所述红黑树模块具体用于:

建立死锁检测红黑树,在计算机程序编译过程中,当建立线程时,将计算机程序链接至所述线程操作函数的重构函数,在所述红黑树中增加当前建立线程对应的节点,获取当前线程,并在所述节点中保存所述线程信息和当前线程的线程标识;

在计算机程序编译过程中,当有加锁操作时,将计算机程序链接至所述锁操作函数的重构函数,在所述死锁检测红黑树中所述锁操作所在线程对应的节点中增加子节点,获取当前锁信息,并在所述子节点中按获取顺序依次保存所述锁信息和对应的锁标识,并标记锁状态为持有状态;

当有解锁操作时,在所述红黑树中对应的线程中查找与解锁操作对应的子节点,清除所述与解锁操作对应的子节点中锁信息的持有状态。

在上述各实施例的基础上,进一步地,还包括:

第一锁位置确定模块,用于遍历所述死锁检测红黑树中的所有子节点,依次获取第i个线程中第j个锁uij在第m个线程中的位置pijm以及所述锁uij在所述第i个线程中的位置piji;

第二锁位置确定模块,用于获取所述第m个线程中第k个锁umk在所述第i个线程中的位置pmki以及所述锁umk在所述第m个线程中的位置pmkm,其中i,j,k,m为整数,且i,m∈[0,n-1],n为所述死锁检测红黑树中记载的线程总数;

计算模块,用于若判断获知sign(i,m)的结果为非负数,则确定所述第i个线程和所述第m个线程没有发生死锁,其中sign(i,m)={(piji-pmki)*(pijm-pmkm)}。

在上述各实施例的基础上,进一步地,还包括:

标记模块,用于若发生死锁,则通过所述死锁检测红黑树获取引起第一线程阻塞的第一锁,并在所述死锁检测红黑树中将所述第一锁对应的子节点标记为扫描状态,并记录标记次数;

扫描模块,用于通过所述死锁检测红黑树查找到持有所述第一锁的所有线程,判断每个持有所述第一锁的线程中引起阻塞的其他锁,并在所述死锁检测红黑树中将所述其他锁对应的子节点标记为扫描状态并记录标记次数,直到所述死锁检测红黑树中所有的子节点均被标记为扫描状态;

相应地,所述定位模块用于若第二锁的标记次数大于预设次数阈值,则将持有所述第二锁的所有线程中的每个锁标记为死锁状态。

本发明实施例提供的装置,用于实现上述方法,其功能具体参照上述方法实施例,此处不再赘述。

本发明实施例提供的内存故障检测装置,在编译过程中链接重构函数获取红黑树需要记载的内存信息和申请内存的模块信息,通过在程序中插入检测代码获取分配的内存信息,支持在线的内存故障检测,引入申请者信息,能够快速定位出现故障的模块,且该内存故障检测方法内存使用少,性能损耗小,有利于在内存资源受限的环境中使用。

本领域普通技术人员可以理解:实现上述方法实施例的全部或部分步骤可以通过程序指令相关的硬件来完成,前述的程序可以存储于计算机可读取存储介质中,该程序在执行时,执行包括上述方法实施例的步骤;而前述的存储介质包括:rom、ram、磁碟或者光盘等各种可以存储程序代码的介质。

以上所描述的装置等实施例仅仅是示意性的,其中所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部模块来实现本实施例方案的目的。本领域普通技术人员在不付出创造性的劳动的情况下,即可以理解并实施。

最后应说明的是:以上各实施例仅用以说明本发明的实施例的技术方案,而非对其限制;尽管参照前述各实施例对本发明的实施例进行了详细的说明,本领域的普通技术人员应当理解:其依然可以对前述各实施例所记载的技术方案进行修改,或者对其中部分或者全部技术特征进行等同替换;而这些修改或者替换,并不使相应技术方案的本质脱离本发明的各实施例技术方案的范围。

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