CN101814049A - 一种内存泄漏探测方法 - Google Patents
一种内存泄漏探测方法 Download PDFInfo
- Publication number
- CN101814049A CN101814049A CN 201010131849 CN201010131849A CN101814049A CN 101814049 A CN101814049 A CN 101814049A CN 201010131849 CN201010131849 CN 201010131849 CN 201010131849 A CN201010131849 A CN 201010131849A CN 101814049 A CN101814049 A CN 101814049A
- Authority
- CN
- China
- Prior art keywords
- virtual machine
- address
- function
- memory
- absorbed
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Pending
Links
Images
Landscapes
- Debugging And Monitoring (AREA)
Abstract
本发明公开了一种内存泄漏探测方法,属于虚拟化技术领域。本发明的方法为:1)虚拟机管理器截获内存资源的申请函数和释放函数的地址,从而获取分配的动态内存信息;2)根据动态内存的起始地址和长度,计算该动态内存所跨越的所有内存监控单元;3)在影子页表中删除对所述内存监控单元的虚拟地址到机器地址的映射关系;4)虚拟机陷入时,虚拟机管理器监测2)中的内存监控单元是否被访问;5)监控策略模块将设定时间内未被应用程序访问的内存监控单元所在的动态内存项视为存在内存泄漏嫌疑的动态内存项。与现有技术相比,本发明能够发现潜在的内存泄露,且不需要修改被探测程序的源代码,也不需要重新编译,为被测试代码提供了透明性。
Description
技术领域
本发明属于虚拟化技术领域,涉及一种内存泄漏探测方法。
背景技术
内存泄露是指被申请的内存资源在程序运行的某一时刻后再也不被使用和释放。如果被泄露的是虚拟内存,则此程序本身能够使用的虚拟内存空间因此变少;如果被泄露的是物理内存,则整个系统减少了能够使用的物理地址。内存泄露会使应用程序申请动态内存失败,导致服务中止;严重时会导致整个系统因资源耗竭而崩溃。对于运行时间很短的程序,内存泄露一般不是问题;但是对于长期运行的程序,例如运行在服务器上的服务和操作系统本身,内存泄露会带来严重的后果,可能会导致系统服务中止。一直以来,内存泄露都是造成计算机安全事故的主要原因之一。
一些编程语言例如Java,通过垃圾回收等方式,自身提供了内存回收的机制。这种机制不但不能保证消除内存泄露,而且还会带来性能的损失。而另外执行效率很高的一些编程语言例如C和C++则将内存分配和释放的操作完全交付给程序员;在逻辑非常庞大的程序中,内存泄露很难避免。因为内存泄露探测的重要性,先前已经有很多这方面的工作。这些工作基本分为两类:第一类是静态检查程序语义。这类方法认为,正确的程序代码,应该符合预定的规则,例如,通过malloc函数申请的内存,在接下来运行的所有代码分支都应该有一个free函数。例如将代码的路径抽象为布尔限制路径,对动态内存的指针加以跟踪。对于大型的工程,这个方法比较耗时,例如分析GNU/Linux的内核代码需要一个处理器一整天的时间。也有将代码抽象为一个变量流通图的,图的边表示代码分支。这类方法直接对代码进行分析,实现复杂,目前还有一些难点尚未解决,例如循环的处理。另一类是运行时动态检测法。即在程序运行时记录程序动态分配的内存资源和释放信息,然后分析是否存在内存泄露。例如Purify和SafeMem,都属于这一类。动态检测法受限于测试程序,因为测试程序所覆盖的代码非常有限,无法激发出所有潜在的问题。本发明就是为了解决这些问题而提出的。
发明内容
针对现有技术方法所存在的问题,本发明的目的在于提供一种内存泄漏探测方法。本发明利用虚拟机管理器,透明地记录应用程序对资源的申请、释放以及使用情况,提供了探测内存泄露的辅助信息。此机制首先不需要修改或重新编译源程序;其次,带来的性能损失很小。两者结合可以构建在线内存泄露探测和汇报机制。不仅如此,基于虚拟环境的内存泄露探测还具备通用性,且不需要特殊的硬件支持。所有这些特性,是已有的解决方案所不能兼有的。实验结果表明:基于虚拟机环境的内存泄露探测机制具有实用性,性能损失也被控制在10%以内,能够运用在实际的生产环境中。
本发明的技术方案为:
一种内存泄漏探测方法,其步骤为:
1)虚拟机管理器截获内存资源的申请函数和释放函数的地址,从而获取分配的动态内存信息;所述动态内存信息包括动态内存的起始地址、长度、访问时间和调用IP地址;
2)根据动态内存的起始地址和长度,计算该动态内存所跨越的所有内存监控单元;
3)在影子页表中删除对所述内存监控单元的虚拟地址到机器地址的映射关系;
4)虚拟机陷入时,虚拟机管理器监测2)中的内存监控单元是否被访问;
5)监控策略模块将设定时间内未被应用程序访问的内存监控单元所在的动态内存项视为存在内存泄漏嫌疑的动态内存项。
进一步的,如果应用程序的某一调用IP地址持续申请动态内存且部分不释放,则将该IP地址所分配的内存项视为发生内存泄漏嫌疑的动态内存项。
进一步的,所述动态内存信息的获取方法为:
1)在函数地址处插入陷入指令;所述陷入指令为能够使得虚拟机陷入到虚拟机管理器的指令;该被植入陷入指令的函数称为受监控函数;
2)运行在虚拟机中的应用程序调用该受监控函数,陷入虚拟机管理器;
3)虚拟机管理器根据该受监控函数的类别更新应用程序占用内存资源的信息;该受监控函数如果是资源申请函数则增加内存占用信息,如果是资源释放函数则删除相应的内存信息;
4)虚拟机管理器模拟执行被替换指令,如果该受监控函数是资源申请函数,则在该陷入指令的下一条指令处再插入一陷入指令;函数地址中被所述陷入指令替换掉的指令称为被替换指令;
5)虚拟机管理器命令该虚拟机继续执行该受监控函数,虚拟机执行结束后,返回到调用处的下一条指令;
6)虚拟机返回到调用处的下一条指令,执行该指令时陷入虚拟机管理器,虚拟机管理器分析该受监控函数返回的结果得到动态内存的起始地址、长度、访问时间,同时根据返回处地址得到调用IP地址。
进一步的,受监控函数的调用IP地址以及该调用IP地址的陷入点类型存放于快速查找树中,通过快速查找树查找所述调用IP地址。
进一步的,虚拟机管理器处理所述陷入指令时,首先判断陷入地址是否在所述快速查找树中,如果在,则查找陷入点的类型:如果陷入点是资源申请函数,则分析并记录其参数,并在返回点处插入一陷入指令,申请成功后记录动态内存信息;如果陷入点是返回点,则分析函数返回结果;如果陷入点是资源释放函数,则将该函数动态内存的分配记录删除。
进一步的,所述虚拟机管理器根据该受监控函数的类别更新应用程序占用内存资源的信息时,获取该受监控函数的调用栈。
进一步的,从调用栈中获取被调用函数返回地址的方法为:虚拟机管理器逐条读取堆栈中的数据,如果该数据落在代码地址空间中,则该数据被认为是被调用函数的返回地址。
进一步的,判断所述内存监控单元是否被访问的方法为:
1)虚拟机管理器在影子页表中清除每个内存监控单元的页表项,同时清除快表;
2)当虚拟机发生缺页中断时,判断被访问地址是否在所需要被监控的内存块,如果在,则记录被访问的时间和类型,解除对此内存块的监控。
进一步的,所述步骤5)的实现方法为:
1)监控策略模块从虚拟机管理器获取当前未被释放的动态内存的信息列表;
2)监控策略模块从所述信息列表中筛选出需要监控的内存段,并发送命令给虚拟机管理器对其进行监控;
3)监控策略模块汇总虚拟机管理器返回的内存段监控信息,将设定时间内未被应用程序访问的动态内存项视为存在内存泄漏嫌疑的动态内存项。
进一步的,所述监控策略模块以进程的方式运行;所述内存监控单元为内存页面。
本发明通过虚拟机管理器平台,记录其上虚拟机运行时动态截获虚拟机中申请和释放内存的函数,记录已被分配且尚未释放的内存信息。通过内存虚拟化技术的协助,我们可以监控应用程序对这些内存资源的应用情况。然后,应用一些规则,找出内存泄露的嫌疑。例如长时间未被释放、且没有被访问的内存可能是内存泄露。
如图1所示,本发明的整个方案主要分为三个部分:1)截获内存资源的申请和释放函数的地址,从而获取分配的内存信息;2)利用内存虚拟化技术对分配的内存进行监控;3)根据规则找出内存泄漏的嫌疑。下面将就这三个部分做进一步的介绍。
1、截获内存资源的申请和释放函数的地址,从而获取分配的动态内存信息
Purify和SafeMem等实现方案通过修改源代码或者修改编译器的方式,来截取资源申请和释放;而通过虚拟化平台可以更简单更透明地实现这个功能。我们以malloc和free为例来说明,下面列出了一小段常见的代码。
void*PTR=malloc(LEN);
if(PTR==NULL)err(“Out of memory.”);
/*utilizing the memory starting at PTR of size LEN*/
if(PTR)free(PTR);
这段c语言代码首先通过malloc函数申请长度为LEN个字节的动态内存,然后判断是否申请成功。如果成功,则使用这些内存资源进行计算。最后,当不再需要PTR所指的资源时,通过free函数释放这些内存。在这个场景中,我们不仅需要截获malloc函数的调用,获取其参数和返回结果,而且也需要截获free函数的调用,获取其参数,也即被释放的动态资源。换句话说,应用程序当前正在使用的动态内存信息,包括其起始地址、长度、时间和调用IP地址都需要在虚拟机管理器中维护。
在虚拟化平台中,可以通过替换指令的方式,即通过将原指令替换成陷入指令的方法,透明地截获申请函数和释放函数。为了实现透明的结果,首先分析一下上面c语言程序在Linux操作系统之上对应的汇编代码:
8048426:89 04 24 mov %eax,(%esp)
8048429:e8 de fe ff ff call 804830c<malloc@p1t>
804842e:89 45 fc mov %eax,0xfffffffc(%ebp)
8048431:83 7d fc 00 cmpl $0x0,0xfffffffc(%ebp)
8048435:75 18 jne 804844f<main+0x4f>
8048437:c7 04 24 54 85 04 08 movl $0x8048554,(%esp)
804843e:e8 e9 fe ff ff call 804832c<printf@plt>
8048443:c7 04 24 01 00 00 00 movl $0x1,(%esp)
804844a:e8 ed fe ff ff call 804833c<exit@plt>
804844f:83 7d fc 00 cmpl $0x0,0xfffffffc(%ebp)
8048453:74 0b je 8048460<main+0x60>
8048455:8b 45 fc mov 0xfffffffc(%ebp),%eax
8048458:89 04 24 mov %eax,(%esp)
804845b:e8 ec fe ff ff call 804834c<free@plt>
可以看到,在地址为0x8048426的地方,变量LEN中保存的数值被压到栈上,接下来的一条指令调用了malloc函数,程序的运行跳转到malloc函数所在的地址0x804830c。在malloc函数返回后,程序在地址0x804842e处继续执行。如果malloc函数申请资源成功,程序最终会在地址0x804845b处调用free函数,释放这段内存空间。
内存资源申请函数和释放函数,例如malloc和free,作为系统的调用接口,其在内存中的地址很容易捕获得到,在上面的示例程序中,malloc和free的地址分别为0x804830c和0x804834c。获得内存申请函数和释放函数的地址之后,截获应用程序当前正在使用的动态内存信息(可参考:Purify:http://www-01.ibm.com/software/awdtools/purify/或者文献:SafeMem:Exploiting ECC-Memory for Detecting Memory Leaks and MemoryCorruption During Production Runs.Feng Qin,Shan Lu and Yuanyuan Zhou.HPCA2005.),本发明中截获应用程序当前正在使用的动态内存信息的方法为:
1)在函数地址处(例如0x804830c处)插入能够使得虚拟机无条件陷入到虚拟机管理器的指令。例如非法指令,在Intel的VT平台中可以插入VMCALL指令。我们把这种指令称为陷入指令,原位置被替换的指令称为被替换指令,把被植入陷入指令的函数称为受监控函数。
2)运行在虚拟机中的应用程序调用受监控函数(例如malloc)之后,虚拟机马上陷入虚拟机管理器。
3)在虚拟机管理器中,分析受监控函数的类别(包括资源申请函数和资源释放函数),分析其参数,获取函数调用栈,更新应用程序占用内存资源的信息。如果是资源申请函数则增加内存占用信息,而资源释放函数则需要删除相应的内存信息。例如,如果陷入的函数是malloc,其只有一个参数表明申请内存的长度,我们可以在当前应用程序的堆栈上获得。如果陷入的是free函数,其参数表明需要释放的内存。这里获取函数调用栈的目的是为了程序员调试的方便。
4)在虚拟机管理器中模拟执行被替换指令。之所以不恢复被替换指令的原因是,为了保证能监控到应用程序并发调用该受监控函数,例如多线程程序中多个线程有可能同时通过调用malloc函数申请内存资源。
5)如果该受监控函数在申请资源,在陷入指令的下一条指令处(在例子中,地址0x804842e处),需要插入陷入指令,以便让我们获悉函数调用结束,分析申请结果。
6)虚拟机管理器命令虚拟机继续执行,虚拟机会执行受监控函数的其它代码(即其它指令),执行结束后,返回到调用处,上例中监控malloc的第一次调用,则是地址0x804842e处。
7)返回处陷入,因为步骤5)已经将一个陷入指令插入到返回处;在虚拟机管理器中,分析受监控函数返回的结果得到动态内存的起始地址、长度、访问时间,同时根据返回处地址得到动态内存的调用IP地址。对于malloc函数,其返回结果是所申请到内存资源的地址,如果申请失败,则返回值是NULL。
通过以上步骤获取应用程序的动态内存资源使用情况之后,我们即时地维护应用程序申请动态内存的列表。如果应用程序中存在内存泄露的话,被泄露的内存必然在我们所维护的表中。从动态内存列表中精确找出被泄露的内存项是一个难点;然而,我们可以先找到疑似泄露的动态内存项,然后将信息(函数调用栈,调用地址和申请资源大小等)交由程序员处理。
2、利用内存虚拟化技术对已分配的动态内存信息进行监控,监测已分配的动态内存是否被访问
内存监控的一个选择是通过管理虚拟机的影子页表实现。在虚拟机运行时,内存管理模块载入影子页表,试图完成从GVA(虚拟地址)到HPA(机器地址)的映射。如果影子页表中已经存在某个GVA到其HPA的映射,那么这个转换过程会自动完成;否则,虚拟机会陷入到虚拟机管理器中,由后者完善GVA到HPA的映射。基于影子页表的这种特征,通过如下步骤即可完成对内存的监控。
首先,根据动态内存信息中的起始地址和长度,计算出内存片断所跨越的所有内存监控单元(此处内存监控单元为页面),例如在页面大小为4K的虚拟机中,首地址为0x80a8400,长度为10KB的内存片断,跨越了3个页面:其中占第一个和第三个页面的部分,完全占用第二个页面(如图2a所示)。接着,在影子页表中消除对这些页面的GVA到HPA的映射关系。因为这些页面的映射关系被消除,那么只要虚拟机试图访问该内存片断,都会导致虚拟机的陷入(如图2b所示)。最后,在虚拟机陷入时,分析陷入指令所访问的内存地址是否属于该内存片断(即所监测的动态内存),如果属于所监测的动态内存,则判定为该动态内存被访问,同时更新其时间信息。
通过内存虚拟化机制实现的内存监控,是基于页面级,即所监控的最小内存单位是内存页。内存页通常大小是4K,也有其它大小,例如2M和4M。在进行监控时,虚拟机对页面范围内的所有内存地址访问都会导致陷入,因此,监控的单位大小越小越好。
基于硬件ECC的监控是更细粒度的监控机制,被SafeMem所采用。如果虚拟机管理器存在ECC的支持,也能够实现cache line大小粒度的监控,SafeMem所使用的方法同样适用于虚拟机管理器。
这种内存监控的原理,也适用于其它内存虚拟化方法,例如直接页表访问。即使是硬件辅助内存虚拟化技术,例如EPT(Extended Page Tables)]或者NPT(Nested Page Tables),也可以在其上实现内存监控。核心思想是通用的,即从虚拟机管理器中,消除虚拟机从GVA到HPA的内存地址映射关系。
3、根据规则找出内存泄漏的嫌疑
我们判断是否是内存泄露的嫌疑基于如下几条规则:
1)在应用程序运行的过程中,如果设定时间内未被应用程序访问的动态内存项视为存在内存泄漏嫌疑的动态内存项;这里的运行是指应用程序实际占用处理器的状态,不包括程序阻塞等待的状态。
2)在应用程序的某一调用IP地址(即调用点)持续申请动态内存且部分不释放(即没有完全释放),导致应用程序占用的动态内存随着运行时间的延续越来越多,则该IP地址所分配的内存项视为发生内存泄漏嫌疑的动态内存项。
规则1基于被泄漏内存的最基本的特征:应用程序在语义层面上,丢弃了内存段并不再访问该内存段。规则1需要虚拟机管理器对应用程序的内存的访问情况进行监控。监控应用程序所申请的所有内存资源的访问是不太实际的,因为这有可能引起大量的虚拟机陷入,严重影响虚拟机管理器的整体性能。为了克服这一点,从而减少虚拟机管理器性能的损失,应当降低被监控内存片断的数目。在本发明的设计中,监控策略会根据动态内存的监控历史、分配时间和虚拟机的性能反馈等因素进行判断。
规则2是基于统计的,不需要监控动态内存的被访问情况,因此开销比规则l少,但是准确性比规则l差。此规则基于这样的观察,内存泄露的点具有重复性,在某一IP点上如果发生过内存泄露,那么在此点上还会发生内存泄露。
我们根据上述规则就可以找到疑似内存泄露的动态内存项,然后将相关信息(函数调用栈,调用地址和申请资源大小等)交由程序员处理,为程序员找出内存泄漏提供了极大的方便。
与现有技术相比,本发明的有益效果是:
1.在线性。根据实验,利用虚拟机管理器探测内存泄露给虚拟机带来的性能损失小于10%,能够在真实服务中使用。测试程序的逻辑是有限的,有些内存泄露只有在真正应用时才能发现。因此较低的性能损失又带来了下面提到的有效性,因为在真实使用中,代码的执行覆盖范围更广,能够发现潜在的内存泄露。
2.有效性。通过实验,在公认的存在内存泄露的开源项目中,确实能够发现内存泄露的嫌疑。
3.透明性。既不需要修改被探测程序的源代码,也不需要重新编译,为被测试代码提供了透明性。而Purlfy和SafeMem,前者通过编译插入指令以获取应用程序访问内存的所有行为,然后这些行为被用于判断内存泄露和内存访问地址越界等问题,后者需要重新封装资源申请和释放函数,甚至需要给操作系统添加新的系统调用,这些需求一定程度上不利于它们的应用。
4.通用性。不仅适用于GNU/Linux操作系统,而且对Windows也使用,不仅适用于用户程序,对操作系统内核也同样适用。
我们使用的测试环境为,Intel CoreTM2 CPU@1.86GHz,双核CPU,2M Cache,2G内存;KVM-84版本,虚拟机中内核版本为Linux2.6.24.3,只配备了一个硬盘分区。SATA硬盘,单网卡。编译器为GCC4.1.1。虚拟机管理器所在的操作系统版本也是Linux2.6.24.3。每次测试时除了受测试虚拟机运行外,无其他虚拟机在执行。虚拟机只配备了一个VCPU(Virtual CPU)。
首先,我们测试了本发明对虚拟机性能的影响;然后,测试了公认的存在内存泄露的开源项目中,内存分配和释放的情况,并分析了内存泄露的嫌疑。
1)性能损失实验
我们设计了两个实验,测试了本发明本身对运行在KVM之上的应用程序性能的影响。实验一测试的程序是常见的编译器GCC4.1.1,我们截获了GCC中的所有的内存申请和释放函数调用。然后分别测试了编译proftpd-1.3.2rc4源代码的时间。实验二是我们设计的程序,该程序调用了6亿次的malloc和free函数。结果见表1。
表1应用程序在虚拟机中的性能对比
Kvm-84 | Kvm-84-memory-leak-detection | |
GCC4.1.1 | 28秒 | 30秒 |
6亿次调用malloc和free | 68.889秒 | 69.083秒 |
由表1可知,具有异常频繁内存申请和释放的GCC4.1.1程序,在正常的KVM虚拟机上编译一个应用程序所需时间为28秒,而在添加了内存泄露探测机制的KVM虚拟机上编译同一个应用程序所需时间为30秒,可见内存泄露探测机制引起的性能损失在10%以内。而对于我们设计的6亿次malloc和free函数调用的程序,内存泄露探测机制引起的性能损失则更少,几乎可以忽略不计。
2)有效性实验
为了测试基于虚拟机管理器进行内存泄露机制的有效性,我们找到了公认存在内存泄露的两个开源项目:proftpd-1.2.9和squid-2.4,并对其分别进行了测试。
测试proftpd-1.2.9的实验环境是:通过多个客户端程序,向服务器发送1000次SIZE命令。因为SIZE命令会导致proftpd发生内存泄露。在测试程序完成后,尚未被proftpd释放的动态内存详细信息见表2。
表2proftpd中未释放内存片段的详细信息
申请内存的IP地址 | 调用函数类型 | 次数 | 长度(字节) |
0x804e559 | malloc() | 29 | 不统一 |
0x804e778 | malloc() | 1 | 8 |
0x8051239 | malloc() | 35 | 绝大部分是524 |
0x80584f8 | realloc() | 1 | 4097 |
从表2中我们可以看出,在IP地址0x804e778和0x80584f8处只有一次没有释放的malloc内存分配,分配的内存长度分别为8个字节和4097个字节;而在IP地址0x804e559和0x8051239处没有释放的malloc分配记录则有数十次,并且在IP地址0x8051239处分配的内存长度绝大部分都是相同的,因此我们可以推测此处很有可能是一个内存泄露点。
测试squid-2.4的方法是同时启动5个客户端程序,每个程序向squid服务连续发送100个请求。在5个客户端程序都结束时,squid服务未释放的动态内存资源见表3。
表3squid中未释放内存片段的详细信息
申请内存的IP地址 | 调用函数类型 | 次数 | 长度(字节) |
0x80a8e4a | calloc() | 113 | 不统一 |
0x80a8f88 | malloc() | 14 | 64 |
0x80a8edf | realloc() | 2 | 192 |
从表3中我们可以看出,在IP地址0x80a8e4a处有上百次的calloc分配都没有释放;在IP地址0x80a8f88处有14次malloc内存分配没有释放,且分配的内存长度都是64字节;而在IP地址0x80a8edf处只有两次realloc内存分配没有释放。
如表2和3所示,存在内存泄露的可能IP地址是非常有限的,通过函数调用栈,调试人员很容易就能够定位存在内存泄露的点。正如上面所说,proftpd测试中,SIZE命令必然会导致内存泄露,所以在表2中的IP地址中,必然存在内存泄露。
附图说明
图1本发明的方法流程图;
图2本发明的内存监控原理。
图2(a)有映射,图2(b)无映射。
具体实施方式
下面是本发明的一个具体的实施方案,该实现是基于开源的全虚拟化虚拟机管理器KVM-84来完成的。KVM是基于GNU/Linux实现的虚拟机管理器,以模块的形式运行在操作系统中。虚拟机表现为操作系统中的一个qemu进程,该进程通过和KVM模块的交互,实现了处理器虚拟化、内存虚拟化以及部分硬件的虚拟化;其它硬件设备如网卡和外存的虚拟化,由qemu实现。因为KVM是操作系统内部的一个模块,所以其调试和运行非常方便,通过模块的动态加载和卸除即可实现更新,这点是xen无法提供的,在其上每次修改都需要重启硬件。
本实验中,虚拟机使用的操作系统是比较主流的Redhat 4.1.1-52版本。接下来讨论实现中的各个细节问题。
资源申请和释放函数地址的获取。存在于用户地址空间的函数例如malloc和free函数,通过调试程序例如GDB即可获取其地址。将应用程序的可执行代码进行反汇编,也很容易察看到这些函数的地址。例如前面的示例代码中,截获malloc的调用,只需要在地址0x804830c处插入VMCALL代码即可。内核函数如vmalloc和vfree等的地址,可在GNU/Linux的sysmap中获取。
通过VMCALL可以将资源申请和释放的函数地址传递到虚拟机管理器中。这些地址是有限的、静态的。而对这些函数的调用点(即调用IP地址)是在虚拟机运行过程中动态发现的,我们需要截获的调用返回点因此也是动态的。因为对这些调用IP地址的查找操作非常频繁,所以我们将这些调用IP地址以及陷入点类型等信息存放在快速查找树中,以提高查找调用IP地址的效率,陷入点即插入陷入指令的地方。
对资源函数调用和返回的截获。在函数的首地址和返回处插入VMCALL指令之后,虚拟机会在这些地址陷入到虚拟机管理器中。陷入原因是VMCALL。我们在处理VMCALL时,判断陷入地址是否在快速查找树中,如果不在,则将其地址及陷入点类型存放到快速查找书中,如果在,则查明陷入点的类型。有三种类型:资源申请函数陷入、资源释放函数陷入和返回点陷入。如果陷入点是资源申请函数,则根据函数中的参数,分析记录所要分配内存的大小和类型,并从进程堆栈中获取返回点地址,另外在返回点处插入VMCALL。如果陷入点是返回点,则需要分析函数返回结果,即从寄存器(一般是EAX寄存器)中获取函数返回值(如果分配成功,返回值是所分配内存的首地址;如果不成功,返回值是0)。函数的返回结果一般存在堆栈上或者寄存器中,不同类型的函数是不一样的,需要区分对待。如果申请成功,需要记录动态内存的信息:首地址、大小、时间和类型等。如果陷入点的类型是资源释放函数,则需要分析函数中需要释放的动态内存的首地址,将该动态内存的分配记录删除。
完成截获后的分析和记录,调用KVM的emulate_instruction函数,模拟执行指令,跳过被插入的VMCALL指令。这里的额外工作是,emulate_instruction函数会读取虚拟机的指令进行模拟,而当前指令是被替换过的VMCALL指令,需要给该函数提供被替换前的指令。解决方法是修改虚拟机管理器读取虚拟机指令的函数,对不同情况进行判断,如果读取指令地址是被我们替换过的地址,则需要返回原始指令。然后把状态从VMM切换到VM,截获工作至此完成。
函数调用栈的获取。当一个函数被调用时,返回地址被压到栈上,然后处理器跳转到被调用的函数处开始执行。当被调用的函数返回时,处理器从原来被压到栈上的返回地址处继续执行。当程序执行的过程中出现多层调用时,栈上就会保存一系列对应的返回地址。由这些返回地址很容易获取到其所在的一系列函数。这一系列函数被称作调用栈。资源分配时,分配函数的调用栈能够辅助程序开发人员分析此函数调用的代码轨迹。对于疑似被泄露的内存,通过其分配函数的调用栈可以,获悉其分配时程序的上下文,从而排查出其是否真的存在内存泄露。
获取函数调用栈的难点在于如何从栈上排查出这些返回地址,因为Intel X86体系结构中,栈上不仅保存着返回地址,还保存着函数的参数。准确地获取函数调用栈需要结合分析应用程序的代码和堆栈上的数据,这种方法比较耗时。本发明采用的是应用在GNU/Linux内核中的方法。该方法逐条读取堆栈中的数据,如果该数据落在代码地址空间中(即被探测程序的代码所占用的地址空间中),则该数据被认为是一个返回地址。在实际的运行过程中,该方法不仅快,而且正确率高。
在KVM的影子页表机制中实现对内存的监控。实现过程需要两个步骤。第一,对于欲监控内存区域所跨越的每个内存监控单元(本实施例中即页面),在影子页表中清除其PageTable Entry(PTE,页表项),使得以后对这些页面的访问会产生Page Fault。因为我们修改了PTE,改变了Guest Virtual Address(GVA)到Host Physical Address(HPA)的映射关系,所以还需要清除快表(TLB),使原来的映射失效。第二步便是Page Fault的处理。在虚拟机发生Page Fault(缺页中断)时,判断被访问地址是否在我们保护的范围内,如果不在所分配的动态内存段范围内,就不需要去修改访问时间。如果在则对于被监控区域的访问,记录被访问时间和类型(读或写),解除对此内存区域的监控。KVM默认的处理程序会为这个页面建立新的PTE,至此监控解除。
监控策略的实现。我们将监控策略模块以进程的方式运行,策略进程和虚拟机模块通过命令进行数据交互,这种实现方式主要基于如下的考虑。首先,监控策略的推断是一个复杂且繁琐的过程,不适合实现在内核中,在进程中实现能够更加灵活。其次,将高层功能从虚拟机管理器中抽取出来,有利于虚拟机管理器的稳定。监控策略模块的工作步骤如下:第一步,监控策略模块向虚拟机管理器发送命令,获取当前未被释放的动态内存的信息列表,包括内存起始地址、长度、申请时间、最后访问时间、类型以及函数调用栈等信息。第二步,监控策略模块从列表中推选出需要监控的内存段(比如超过一定时间没有释放的内存段、或在同一IP地址多次申请且不释放的内存段),发送命令给虚拟机管理器。最后,监控策略模块汇总内存段的各种信息,判断其是否存在内存泄露嫌疑(比如经过监控之后所得到的是否有被访问的信息,如果一直都没有被访问,则就有可能是内存泄漏)。
本发明所提出的利用虚拟机管理器进行内存泄漏探测的方法,其主要技术特征是在虚拟机平台中通过在虚拟机(Guest OS)中插入指令的方式,透明地拦截应用程序申请和释放内存资源的函数调用,维护应用程序所使用动态内存资源的列表。从这个列表中推选出一部分,进行访问的监控。那些长时间不被释放且不被访问的内存资源,则是很好的内存泄露的嫌疑。为了减少监控内存访问的性能损失,本发明作了一些重要的优化,例如放弃对热页面的监控。因此,凡是符合通过虚拟机管理器进行内存泄漏探测的技术都在本专利的保护范围之内。
Claims (10)
1.一种内存泄漏探测方法,其步骤为:
1)虚拟机管理器截获内存资源的申请函数和释放函数的地址,从而获取分配的动态内存信息;所述动态内存信息包括动态内存的起始地址、长度、访问时间和调用IP地址;
2)根据动态内存的起始地址和长度,计算该动态内存所跨越的所有内存监控单元;
3)在影子页表中删除对所述内存监控单元的虚拟地址到机器地址的映射关系;
4)虚拟机陷入时,虚拟机管理器监测2)中的内存监控单元是否被访问;
5)监控策略模块将设定时间内未被应用程序访问的内存监控单元所在的动态内存项视为存在内存泄漏嫌疑的动态内存项。
2.如权利要求1所述的方法,其特征在于如果应用程序的某一调用IP地址持续申请动态内存且部分不释放,则将该IP地址所分配的内存项视为发生内存泄漏嫌疑的动态内存项。
3.如权利要求1所述的方法,其特征在于所述动态内存信息的获取方法为:
1)在函数地址处插入陷入指令;所述陷入指令为能够使得虚拟机陷入到虚拟机管理器的指令;该被植入陷入指令的函数称为受监控函数;
2)运行在虚拟机中的应用程序调用该受监控函数,陷入虚拟机管理器;
3)虚拟机管理器根据该受监控函数的类别更新应用程序占用内存资源的信息;该受监控函数如果是资源申请函数则增加内存占用信息,如果是资源释放函数则删除相应的内存信息;
4)虚拟机管理器模拟执行被替换指令,如果该受监控函数是资源申请函数,则在该陷入指令的下一条指令处再插入一陷入指令;函数地址中被所述陷入指令替换掉的指令称为被替换指令;
5)虚拟机管理器命令该虚拟机继续执行该受监控函数,虚拟机执行结束后,返回到调用处的下一条指令;
6)虚拟机返回到调用处的下一条指令,执行该指令时陷入虚拟机管理器,虚拟机管理器分析该受监控函数返回的结果得到动态内存的起始地址、长度、访问时间,同时根据返回处地址得到调用IP地址。
4.如权利要求3所述的方法,其特征在于受监控函数的调用IP地址以及该调用IP地址的陷入点类型存放于快速查找树中,通过快速查找树查找所述调用IP地址。
5.如权利要求4所述的方法,其特征在于虚拟机管理器处理所述陷入指令时,首先判断陷入地址是否在所述快速查找树中,如果在,则查找陷入点的类型:如果陷入点是资源申请函数,则分析并记录其参数,并在返回点处插入一陷入指令,申请成功后记录动态内存信息;如果陷入点是返回点,则分析函数返回结果;如果陷入点是资源释放函数,则将该函数动态内存的分配记录删除。
6.如权利要求3所述的方法,其特征在于所述虚拟机管理器根据该受监控函数的类别更新应用程序占用内存资源的信息时,获取该受监控函数的调用栈。
7.如权利要求6所述的方法,其特征在于从调用栈中获取被调用函数返回地址的方法为:虚拟机管理器逐条读取堆栈中的数据,如果该数据落在代码地址空间中,则该数据被认为是被调用函数的返回地址。
8.如权利要求1所述的方法,其特征在于判断所述内存监控单元是否被访问的方法为:
1)虚拟机管理器在影子页表中清除每个内存监控单元的页表项,同时清除快表;
2)当虚拟机发生缺页中断时,判断被访问地址是否在所需要被监控的内存块,如果在,则记录被访问的时间和类型,解除对此内存块的监控。
9.如权利要求1所述的方法,其特征在于所述步骤5)的实现方法为:
1)监控策略模块从虚拟机管理器获取当前未被释放的动态内存的信息列表;
2)监控策略模块从所述信息列表中筛选出需要监控的内存段,并发送命令给虚拟机管理器对其进行监控;
3)监控策略模块汇总虚拟机管理器返回的内存段监控信息,将设定时间内未被应用程序访问的动态内存项视为存在内存泄漏嫌疑的动态内存项。
10.如权利要求1所述的方法,其特征在于所述监控策略模块以进程的方式运行;所述内存监控单元为内存页面。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN 201010131849 CN101814049A (zh) | 2010-03-23 | 2010-03-23 | 一种内存泄漏探测方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN 201010131849 CN101814049A (zh) | 2010-03-23 | 2010-03-23 | 一种内存泄漏探测方法 |
Publications (1)
Publication Number | Publication Date |
---|---|
CN101814049A true CN101814049A (zh) | 2010-08-25 |
Family
ID=42621310
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN 201010131849 Pending CN101814049A (zh) | 2010-03-23 | 2010-03-23 | 一种内存泄漏探测方法 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN101814049A (zh) |
Cited By (24)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN102736969A (zh) * | 2012-05-22 | 2012-10-17 | 中国科学院计算技术研究所 | 一种针对硬件虚拟化的内存监控方法和系统 |
CN103577335A (zh) * | 2013-10-23 | 2014-02-12 | 中国科学院计算技术研究所 | 一种内存垃圾回收系统及方法 |
WO2014201939A1 (zh) * | 2013-06-21 | 2014-12-24 | 中兴通讯股份有限公司 | 内存监控处理方法及装置 |
CN104484606A (zh) * | 2014-12-05 | 2015-04-01 | 国云科技股份有限公司 | 一种虚拟化平台内存信息保密性的验证方法 |
WO2015101148A1 (zh) * | 2013-12-30 | 2015-07-09 | 华为技术有限公司 | 一种实现虚拟机自省的方法和装置 |
CN105303115A (zh) * | 2015-10-29 | 2016-02-03 | 成都信息工程大学 | 一种Java卡越界访问漏洞的检测方法和装置 |
CN105843667A (zh) * | 2016-03-02 | 2016-08-10 | 南京大学 | 在虚拟机管理器中动态无侵的应用进程函数调用监控方法 |
CN105912458A (zh) * | 2016-03-28 | 2016-08-31 | 中国电力科学研究院 | 一种用于动态检测c/c++内存泄露的方法及系统 |
CN106055478A (zh) * | 2016-05-31 | 2016-10-26 | 腾讯科技(深圳)有限公司 | 检测内存泄漏的方法和装置 |
CN106130719A (zh) * | 2016-07-21 | 2016-11-16 | 中国科学院信息工程研究所 | 一种抵抗内存泄漏攻击的密码算法多核实现方法及装置 |
CN106407031A (zh) * | 2016-09-14 | 2017-02-15 | 华为数字技术(成都)有限公司 | 一种内存泄露定位方法及电子设备 |
CN107133144A (zh) * | 2017-05-02 | 2017-09-05 | 山东浪潮商用系统有限公司 | 一种动态监测堆内存使用错误的内存监测装置及方法 |
CN107391234A (zh) * | 2017-08-10 | 2017-11-24 | 西安电子科技大学 | 一种基于vmi的文件系统细粒度监控方法 |
CN108121602A (zh) * | 2017-12-14 | 2018-06-05 | 捷开通讯(深圳)有限公司 | 一种确定垃圾收集触发点的方法、电子设备及存储介质 |
CN108287781A (zh) * | 2017-01-10 | 2018-07-17 | 腾讯科技(深圳)有限公司 | 一种内存占用监控方法及装置、系统 |
CN109471771A (zh) * | 2018-10-19 | 2019-03-15 | 许昌许继软件技术有限公司 | 一种Nucleus系统的动态内存池监测方法及装置 |
CN109542778A (zh) * | 2018-11-12 | 2019-03-29 | 中国银联股份有限公司 | 一种资源泄露检测的方法及装置 |
CN109933525A (zh) * | 2019-02-22 | 2019-06-25 | 深圳市吉祥腾达科技有限公司 | 一种通用的内存泄露检测方法 |
CN110032464A (zh) * | 2019-03-15 | 2019-07-19 | 北京星网锐捷网络技术有限公司 | 内存泄露的处理方法及装置 |
CN111858112A (zh) * | 2019-04-26 | 2020-10-30 | 腾讯科技(深圳)有限公司 | 一种检测内存泄露的方法、客户端及服务器 |
CN112100022A (zh) * | 2020-08-14 | 2020-12-18 | 北京航空航天大学 | 一种安卓系统上监测Java对象内存泄漏时即时记录对象分配点的方法 |
CN113297074A (zh) * | 2021-05-21 | 2021-08-24 | 百果园技术(新加坡)有限公司 | 一种内存跟踪方法及装置 |
CN113868673A (zh) * | 2021-12-06 | 2021-12-31 | 荣耀终端有限公司 | 漏洞检测方法和装置 |
WO2022262530A1 (zh) * | 2021-06-16 | 2022-12-22 | 荣耀终端有限公司 | 内存管理的方法及电子设备 |
Citations (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1466057A (zh) * | 2002-06-20 | 2004-01-07 | 华为技术有限公司 | 一种软件内存泄露的检查方法 |
CN101145128A (zh) * | 2007-06-13 | 2008-03-19 | 中兴通讯股份有限公司 | 一种检测内存泄露的方法 |
-
2010
- 2010-03-23 CN CN 201010131849 patent/CN101814049A/zh active Pending
Patent Citations (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1466057A (zh) * | 2002-06-20 | 2004-01-07 | 华为技术有限公司 | 一种软件内存泄露的检查方法 |
CN101145128A (zh) * | 2007-06-13 | 2008-03-19 | 中兴通讯股份有限公司 | 一种检测内存泄露的方法 |
Non-Patent Citations (1)
Title |
---|
《计算机学报》 20100312 汪小林等 利用虚拟化平台进行内存泄露探测 463-472 1-10 第33卷, 第3期 2 * |
Cited By (36)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN102736969B (zh) * | 2012-05-22 | 2014-12-17 | 中国科学院计算技术研究所 | 一种针对硬件虚拟化的内存监控方法和系统 |
CN102736969A (zh) * | 2012-05-22 | 2012-10-17 | 中国科学院计算技术研究所 | 一种针对硬件虚拟化的内存监控方法和系统 |
WO2014201939A1 (zh) * | 2013-06-21 | 2014-12-24 | 中兴通讯股份有限公司 | 内存监控处理方法及装置 |
CN103577335B (zh) * | 2013-10-23 | 2016-09-07 | 中国科学院计算技术研究所 | 一种内存垃圾回收系统及方法 |
CN103577335A (zh) * | 2013-10-23 | 2014-02-12 | 中国科学院计算技术研究所 | 一种内存垃圾回收系统及方法 |
WO2015101148A1 (zh) * | 2013-12-30 | 2015-07-09 | 华为技术有限公司 | 一种实现虚拟机自省的方法和装置 |
US10007785B2 (en) | 2013-12-30 | 2018-06-26 | Huawei Technologies Co., Ltd. | Method and apparatus for implementing virtual machine introspection |
CN104484606A (zh) * | 2014-12-05 | 2015-04-01 | 国云科技股份有限公司 | 一种虚拟化平台内存信息保密性的验证方法 |
CN105303115A (zh) * | 2015-10-29 | 2016-02-03 | 成都信息工程大学 | 一种Java卡越界访问漏洞的检测方法和装置 |
CN105843667B (zh) * | 2016-03-02 | 2019-01-15 | 南京大学 | 在虚拟机管理器中动态无侵的应用进程函数调用监控方法 |
CN105843667A (zh) * | 2016-03-02 | 2016-08-10 | 南京大学 | 在虚拟机管理器中动态无侵的应用进程函数调用监控方法 |
CN105912458A (zh) * | 2016-03-28 | 2016-08-31 | 中国电力科学研究院 | 一种用于动态检测c/c++内存泄露的方法及系统 |
CN106055478A (zh) * | 2016-05-31 | 2016-10-26 | 腾讯科技(深圳)有限公司 | 检测内存泄漏的方法和装置 |
CN106130719A (zh) * | 2016-07-21 | 2016-11-16 | 中国科学院信息工程研究所 | 一种抵抗内存泄漏攻击的密码算法多核实现方法及装置 |
CN106407031A (zh) * | 2016-09-14 | 2017-02-15 | 华为数字技术(成都)有限公司 | 一种内存泄露定位方法及电子设备 |
CN106407031B (zh) * | 2016-09-14 | 2019-05-28 | 华为数字技术(成都)有限公司 | 一种内存泄露定位方法及电子设备 |
CN108287781B (zh) * | 2017-01-10 | 2022-08-26 | 腾讯科技(深圳)有限公司 | 一种内存占用监控方法及装置、系统 |
CN108287781A (zh) * | 2017-01-10 | 2018-07-17 | 腾讯科技(深圳)有限公司 | 一种内存占用监控方法及装置、系统 |
CN107133144A (zh) * | 2017-05-02 | 2017-09-05 | 山东浪潮商用系统有限公司 | 一种动态监测堆内存使用错误的内存监测装置及方法 |
CN107133144B (zh) * | 2017-05-02 | 2020-03-17 | 山东浪潮商用系统有限公司 | 一种动态监测堆内存使用错误的内存监测装置及方法 |
CN107391234A (zh) * | 2017-08-10 | 2017-11-24 | 西安电子科技大学 | 一种基于vmi的文件系统细粒度监控方法 |
CN108121602A (zh) * | 2017-12-14 | 2018-06-05 | 捷开通讯(深圳)有限公司 | 一种确定垃圾收集触发点的方法、电子设备及存储介质 |
CN108121602B (zh) * | 2017-12-14 | 2022-05-06 | 捷开通讯(深圳)有限公司 | 一种确定垃圾收集触发点的方法、电子设备及存储介质 |
CN109471771A (zh) * | 2018-10-19 | 2019-03-15 | 许昌许继软件技术有限公司 | 一种Nucleus系统的动态内存池监测方法及装置 |
CN109542778A (zh) * | 2018-11-12 | 2019-03-29 | 中国银联股份有限公司 | 一种资源泄露检测的方法及装置 |
CN109933525A (zh) * | 2019-02-22 | 2019-06-25 | 深圳市吉祥腾达科技有限公司 | 一种通用的内存泄露检测方法 |
CN110032464A (zh) * | 2019-03-15 | 2019-07-19 | 北京星网锐捷网络技术有限公司 | 内存泄露的处理方法及装置 |
CN110032464B (zh) * | 2019-03-15 | 2023-06-16 | 北京星网锐捷网络技术有限公司 | 内存泄露的处理方法及装置 |
CN111858112A (zh) * | 2019-04-26 | 2020-10-30 | 腾讯科技(深圳)有限公司 | 一种检测内存泄露的方法、客户端及服务器 |
CN111858112B (zh) * | 2019-04-26 | 2023-04-25 | 腾讯科技(深圳)有限公司 | 一种检测内存泄露的方法、客户端及服务器 |
CN112100022A (zh) * | 2020-08-14 | 2020-12-18 | 北京航空航天大学 | 一种安卓系统上监测Java对象内存泄漏时即时记录对象分配点的方法 |
CN113297074A (zh) * | 2021-05-21 | 2021-08-24 | 百果园技术(新加坡)有限公司 | 一种内存跟踪方法及装置 |
CN113297074B (zh) * | 2021-05-21 | 2023-12-22 | 百果园技术(新加坡)有限公司 | 一种内存跟踪方法及装置 |
WO2022262530A1 (zh) * | 2021-06-16 | 2022-12-22 | 荣耀终端有限公司 | 内存管理的方法及电子设备 |
CN113868673A (zh) * | 2021-12-06 | 2021-12-31 | 荣耀终端有限公司 | 漏洞检测方法和装置 |
CN113868673B (zh) * | 2021-12-06 | 2022-04-19 | 荣耀终端有限公司 | 漏洞检测方法和装置 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN101814049A (zh) | 一种内存泄漏探测方法 | |
Kim et al. | Fully automatic stream management for {Multi-Streamed}{SSDs} using program contexts | |
US8938729B2 (en) | Two pass automated application instrumentation | |
CN103064784B (zh) | 面向Xen环境的运行时内存泄漏检测方法及其实现系统 | |
Novark et al. | Efficiently and precisely locating memory leaks and bloat | |
US10061918B2 (en) | System, apparatus and method for filtering memory access logging in a processor | |
CN102651062A (zh) | 基于虚拟机架构的恶意行为跟踪系统和方法 | |
CN107111548B (zh) | 硬件辅助的对象存储器迁移 | |
US20100333206A1 (en) | Protecting a software component using a transition point wrapper | |
US8489652B2 (en) | Tracking object fields using relocatable object watchpoints | |
Tang et al. | {LeakSurvivor}: Towards Safely Tolerating Memory Leaks for {Garbage-Collected} Languages | |
Wang et al. | Dynamic memory balancing for virtualization | |
Oh et al. | MaPHeA: A Framework for Lightweight Memory Hierarchy-aware Profile-guided Heap Allocation | |
US11030075B2 (en) | Efficient register breakpoints | |
Wang et al. | Memento: Architectural Support for Ephemeral Memory Management in Serverless Environments | |
EP4278265B1 (en) | Memory address compression within an execution trace | |
US20090031100A1 (en) | Memory reallocation in a computing environment | |
EP4298525A1 (en) | Processor support for using cache way-locking to simultaneously record plural execution contexts into independent execution traces | |
CN115485668A (zh) | 存储器页标记作为基于处理器的执行跟踪的日志记录线索 | |
Zhang et al. | PTAT: An efficient and precise tool for tracing and profiling detailed TLB misses | |
US20230161678A1 (en) | Classification of different types of cache misses | |
EP4268082B1 (en) | Logging cache line lifetime hints when recording bit-accurate trace | |
Vitali et al. | Benchmarking memory management capabilities within ROOT-Sim | |
Young | Persistent memory storage of cold regions in the OpenJ9 Java virtual machine | |
Goncalves | A Performance Comparison of Modern Garbage Collectors for Big Data Environments |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
C02 | Deemed withdrawal of patent application after publication (patent law 2001) | ||
WD01 | Invention patent application deemed withdrawn after publication |
Open date: 20100825 |