一种监控应用程序内存的方法、装置及电子设备与流程

文档序号:11475639阅读:222来源:国知局
一种监控应用程序内存的方法、装置及电子设备与流程

本申请涉及计算机技术领域,具体涉及一种监控应用程序内存的方法以及一种监控应用程序内存的装置;本申请同时涉及一种电子设备。



背景技术:

随着现代系统规模日益扩大,系统中运行的应用程序数量显著增加。这些应用程序通常都会消耗一定量的资源,比如内存。其中某些应用程序有可能会造成内存泄漏、对象doublefree以及访问地址越界等,在计算机科学中,内存泄露是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄露并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费;doublefree其实就是同一个指针释放两次,虽然一般把它叫做doublefree,其实只要是多次释放一个指向堆内存的指针都有可能产生漏洞;访问地址越界是向系统申请了一块内存,在使用这块内存的时候,超出了申请的范围。造成的直接后果是修改了其它内存块的内容,如果被修改的地址是正在使用中内存,会造成应用程序异常。

在应用程序开发的过程中,由于往往需要随着业务流或控制流的处理而进行大量的内存申请和释放,很容易造成在一些异常分支中遗漏释放而出现内存泄露的情形,然而这种内存泄露的事件一般都是少量、且隐蔽的,需要经过很长时间的积累甚至已经造成了严重后果才能被察觉,难以检测和恢复泄露的内存。

目前,虽然已经有一些辅助工具可以协助进行内存泄漏、对象doublefree以及访问地址越界的检测。在现有技术下检测内存的常用工具包括:valgrind、glibc的mtrace/muntrace功能以及tcmalloc。其中,valgrind的执行不需要重新编译,而是和应用程序在同一个进程中,动态的修改即将执行的代码,但正是因为valgrind的工作方式,导致程序性能骤降,根据注入代码量的不同,性能会下降10-50倍,因为其对性能的影响,降低了其在复杂系统中的可用性;glibc的mtrace/muntrace功能利用malloc_hook机制,需要在记录完成后重置malloc_hook函数,所以其只能工作在单进程程序中,对于多进程程序因为 malloc_hook函数更改混乱会造成误报或漏报,所以对于复杂的大型应用程序可用性不高;tcmalloc可以检查程序中是否有内存泄露及内存泄露点信息以及内存性能及空间热点分析,帮助分析内存的使用分布情况。但需要调用backtrace函数获取调用栈信息,而这个操作是一个慢操作,所以tcmalloc使用采样的方式降低对应用程序性能的影响,而采样就可能存在偏差,从而影响结果的可靠性。

由此可见,在现有的监控内存的方案下,由于误报、漏报或者由于其插桩的实现方法或算法复杂性因素引起程序运行缓慢降低性能的问题,从而影响结果的可靠性,对于复杂的大型应用程序可用性不高,并且使用成本较高。



技术实现要素:

本申请提供一种监控应用程序内存的方法以及一种监控应用程序内存的装置,以解决现有技术中的上述问题。本申请同时涉及一种电子设备。

本申请提供了一种监控应用程序内存的方法,所述监控应用程序内存的方法包括:

应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间;

对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息;

对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息。

可选的,在所述应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间的步骤之前,包括:

将预设的重载函数库链接到应用程序中。

可选的,所述预设的重载函数库,至少包括如下内存管理函数:

内存分配函数、内存释放函数以及内存调整函数。

可选的,所述将预设的重载函数库链接到应用程序中,包括:

若所述应用程序是采用静态链接的应用程序,则在编译时将静态链接库链接进应用程序;

若所述应用程序是采用动态连接的应用程序,则在编译时将动态链接库链接进应用程序或者应用程序运行时,通过注入的方式把动态链接库注入应用程序。

可选的,所述应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间,包括:

应用程序调用所述预设的重载函数库中的内存管理函数申请内存运行空间时,所述内存管理函数在内存中额外请求预设大小的内存监控空间。

可选的,所述额外请求预设大小的内存监控空间是:用于记录内存信息的大小为16字节的标签。

可选的,所述标签记录的信息,至少包括:

内存块状态、内存分配栈标识、时间戳、线程标识、桶标识以及标签标识。

可选的,所述对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息,包括:

应用程序调用所述预设的重载函数库中的内存管理函数分配申请的内存运行空间时,判断所述内存管理函数是否成功分配申请的内存运行空间;

若是,则在所述标签中记录本次内存分配信息。

可选的,所述在所述标签中记录本次内存分配信息,包括:

将所述标签中的内存块状态设置为已分配状态;

调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的函数调用栈的标识;

获取对申请的内存运行空间进行分配时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行分配时的当前系统时间;

获取对申请的内存运行空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对申请的内存运行空间进行请求的线程标识;

根据申请的内存运行空间的大小,将所述内存运行空间进行分桶操作,并按照分桶操作的顺序对每个桶设置桶标识,在所述标签中的桶标识中记录当前内存大小对应桶的桶标识;

将所述标签中的标签标识设置为已添加标签的标识。

可选的,所述对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息,包括:

应用程序调用所述预设的重载函数库中的内存管理函数释放申请的内存运行空间时,在所述标签中记录本次内存释放信息。

可选的,所述在所述标签中记录本次内存释放信息,包括:

将所述标签中的内存块状态设置为已释放状态;

调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的内存块的释放函数调用栈的标识;

获取对申请的内存运行空间进行释放时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行释放时的当前系统时间;

获取对释放的内存空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对释放的内存空间进行请求的线程标识;

将所述标签中的标签标识设置为已添加标签的标识。

可选的,所述调用回溯函数获取函数调用栈的标识,包括:

采用编译器开关记录回溯函数获取函数调用栈的标识。

可选的,所述采用编译器开关记录回溯函数获取函数调用栈的标识,包括:

在每个函数调用的出入口调用跟踪函数;

通过栈记录所述跟踪函数调用返回地址,通过回溯函数汇总栈信息获取调用栈的标识。

可选的,在所述标签中记录本次内存释放信息的步骤之前,包括:

判断所述标签中的内存块状态是否为已分配状态;

若是,则执行所述在所述标签中记录本次内存释放信息的步骤;

若否,则调用终止函数结束该应用程序,并转储保存进程信息。

可选的,在所述在每个函数调用的出入口调用跟踪函数的步骤之前,还包括:

在所述跟踪函数中预设内存写坏的判断条件;

在所述在每个函数调用的出入口调用跟踪函数的步骤之后,包括:

判断内存块是否满足预设内存写坏的判断条件;

若是,则调用终止函数结束该应用程序,并转储保存进程信息;

若否,则执行所述通过栈记录所述跟踪函数调用返回地址,并通过回溯函数汇总栈信息获取调用栈的标识的步骤。

可选的,在所述对申请的内存运行空间进行分配或释放时,还包括:

根据在应用程序中已经运行的进程的内存镜像信息,创建与该进程内存镜像相同的子进程。

可选的,当应用程序发生异常时,获取当前应用程序的内存布局,可以采用如下方式实现:

调用终止函数使子进程终止运行,并转存进程信息获取应用程序的内存布局。

相应的,本申请还提供了一种监控应用程序内存的装置,所述监控应用程序内存的装置包括:

监控空间请求单元,用于应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间;

内存分配信息记录单元,用于对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息;

内存释放信息记录单元,用于对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息。

可选的,所述监控应用程序内存的装置,还包括:

重载函数库链接单元,用于在所述应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间之前,将预设的重载函数库链接到应用程序中。

可选的,所述重载函数库链接单元,链接到应用程序中的至少包括如下内存管理函数:内存分配函数、内存释放函数以及内存调整函数。

可选的,所述重载函数库链接单元,包括:

静态链接子单元,用于若所述应用程序是采用静态链接的应用程序,则在编译时将静态链接库链接进应用程序;

动态链接子单元,用于若所述应用程序是采用动态连接的应用程序,则在编译时将动态链接库链接进应用程序或者应用程序运行时,通过注入的方式把动态链接库注入应用程序。

可选的,所述监控空间请求单元,具体用于应用程序调用所述预设的重载函数库中的内存管理函数申请内存运行空间时,所述内存管理函数在内存中额外 请求预设大小的内存监控空间。

可选的,所述监控空间请求单元,具体用于应用程序调用所述预设的重载函数库中的内存管理函数申请内存运行空间时,所述内存管理函数在内存中额外请求用于记录内存信息的大小为16字节的标签。

可选的,所述内存分配信息记录单元,包括:

判断子单元,用于应用程序调用所述预设的重载函数库中的内存管理函数分配申请的内存运行空间时,判断所述内存管理函数是否成功分配申请的内存运行空间;

内存分配信息记录子单元,用于接收所述判断子单元的判断结果,若是,则在所述标签中记录本次内存分配信息。

可选的,所述内存分配信息记录子单元,包括:

已分配状态设置子单元,用于将所述标签中的内存块状态设置为已分配状态;

调用栈标识设置子单元,用于调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的函数调用栈的标识;

时间设置子单元,用于获取对申请的内存运行空间进行分配时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行分配时的当前系统时间;

线程标识设置子单元,用于获取对申请的内存运行空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对申请的内存运行空间进行请求的线程标识;

桶标识设置子单元,用于根据申请的内存运行空间的大小,将所述内存运行空间进行分桶操作,并按照分桶操作的顺序对每个桶设置桶标识,在所述标签中的桶标识中记录当前内存大小对应桶的桶标识;

标签标识设置子单元,用于将所述标签中的标签标识设置为已添加标签的标识。

可选的,所述内存释放信息记录单元,具体用于应用程序调用所述预设的重载函数库中的内存管理函数释放申请的内存运行空间时,在所述标签中记录本次内存释放信息。

可选的,所述内存释放信息记录单元,包括:

已释放状态设置子单元,用于将所述标签中的内存块状态设置为已释放状态;

调用栈标识设置子单元,用于调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的内存块的释放函数调用栈的标识;

释放时间设置子单元,用于获取对申请的内存运行空间进行释放时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行释放时的当前系统时间;

线程标识更新子单元,用于获取对释放的内存空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对释放的内存空间进行请求的线程标识;

标签标识添加子单元,用于将所述标签中的标签标识设置为已添加标签的标识。

可选的,所述调用栈标识设置子单元,具体用于采用编译器开关记录回溯函数获取的函数调用栈的标识。

可选的,所述调用栈标识设置子单元,包括:

跟踪函数调用子单元,用于在每个函数调用的出入口调用跟踪函数;

标识获取子单元,用于通过栈记录所述跟踪函数调用返回地址,通过回溯函数汇总栈信息获取调用栈的标识。

可选的,所述监控应用程序内存的装置,还包括:

状态判断单元,用于在所述在所述标签中记录本次内存释放信息之前,判断所述标签中的内存块状态是否为已分配状态;

内存释放信息记录触发单元,用于接收所述状态判断单元的判断结果,若是,则执触发所述内存释放信息记录单元;

终止函数调用单元,用于接收所述状态判断单元的判断结果,若否,则调用终止函数结束该应用程序,并转储保存进程信息。

可选的,所述监控应用程序内存的装置,还包括:

条件设置单元,用于在所述在每个函数调用的出入口调用跟踪函数之前,在所述跟踪函数中预设内存写坏的判断条件;

条件判断单元,用于在所述在每个函数调用的出入口调用跟踪函数之后,判断内存块是否满足预设内存写坏的判断条件;

终止函数调用单元,用于接收所述条件判断单元的判断结果,若是,则调用终止函数结束该应用程序,并转储保存进程信息;

标识接收触发单元,用于接收所述条件判断单元的判断结果,若否,则触发所述标识获取子单元。

可选的,所述内存分配信息记录单元,还包括:

子进程创建子单元,用于在所述对申请的内存运行空间进行分配或释放时,根据在应用程序中已经运行的进程的内存镜像信息,创建与该进程内存镜像相同的子进程。

可选的,所述监控应用程序内存的装置,还包括:

内存信息获取单元,用于当应用程序发生异常时,调用终止函数使子进程终止运行,并转存进程信息获取应用程序的内存布局。

此外,本申请还提供了一种电子设备,包括:

显示器;

处理器;

存储器,用于存储内存监控程序,所述程序在被所述处理器读取执行时,执行如下操作:应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间;对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息;对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息。

与现有技术相比,本申请具有以下优点:

本申请提供的一种监控应用程序内存的方法、装置以及一种电子设备,通过申请内存空间时,在内存中额外请求预设大小的内存空间;对申请的内存空间进行分配时,在额外请求的内存空间中记录本次内存分配信息;对申请的内存空间进行释放时,在额外请求的内存空间中记录本次内存释放信息。所述技术方案解决了由于误报、漏报或者由于其插桩的实现方法或算法复杂性因素引起程序运行缓慢降低性能的问题,从而提高了结果的可靠性,解决了c/c++程序内存使用中遇到的多种问题,对于复杂的大型应用程序可用性高,并且使用成本较低。

附图说明

为了更清楚地说明本申请实施例或现有技术中的技术方案,下面将对实施例或现有技术描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本申请中记载的一些实施例,对于本领域普通技术人员来讲,还可以根据这些附图获得其他的附图。

图1示出了根据本申请的实施例提供的监控应用程序内存的方法的流程图;

图2示出了根据本申请的实施例提供的对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息的方法的流程图;

图3示出了根据本申请的实施例提供的在所述标签中记录本次内存分配信息的方法的流程图;

图4示出了根据本申请的实施例提供的采用编译器将回溯函数注入应用程序获取函数调用栈的标识的方法的流程图;

图5示出了根据本申请的实施例提供的在所述标签中记录本次内存释放信息的方法的流程图;

图6示出了根据本申请的实施例提供的监控应用程序内存的装置的示意图;

图7示出了根据本申请的实施例提供的电子设备的示意图。

具体实施方式

为了能够更清楚地理解本申请的上述目的、特征和优点,下面结合附图和具体实施方式对本申请进行进一步的详细描述。需要说明的是,在不冲突的情况下,本申请的实施例及实施例中的特征可以相互组合。

在下面的描述中阐述了很多具体细节以便于充分理解本申请。但是,本申请能够以很多不同于在此描述的其它方式来实施,本领域技术人员可以在不违背本申请内涵的情况下做类似推广,因此,本申请不受下面公开的具体实施的限制。

本申请的实施例提供了一种监控应用程序内存的方法以及一种监控应用程序内存的装置,本申请的实施例同时提供了一种电子设备。在下面的实施例中逐一进行详细说明。

目前,虽然已经有一些辅助工具可以协助进行内存泄漏、对象doublefree以及访问地址越界的检测。在现有技术下检测内存的常用工具包括:valgrind、glibc的mtrace/muntrace功能以及tcmalloc。其中,valgrind的执行不需要重新编译,而是和应用程序在同一个进程中,动态的修改即将执行的代码,但正是因为valgrind的工作方式,导致程序性能骤降,根据注入代码量的不同,性能会下降10-50倍,因为其对性能的影响,降低了其在复杂系统中的可用性;glibc的mtrace/muntrace功能利用malloc_hook机制,需要在记录完成后重置malloc_hook函数,所以其只能工作在单进程程序中,对于多进程程序因为malloc_hook函数更改混乱会造成误报或漏报,所以对于复杂的大型应用程序可用性不高;tcmalloc可以检查程序中是否有内存泄露及内存泄露点信息以及内存性能及空间热点分析,帮助分析内存的使用分布情况。但需要调用backtrace函数获取调用栈信息,而这个操作是一个慢操作,所以tcmalloc使用采样的方式降低对应用程序性能的影响,而采样就可能存在偏差,从而影响结果的可靠性。由此可见,在现有的监控内存的方案下,由于误报、漏报或者由于其插桩的实现方法或算法复杂性因素引起程序运行缓慢降低性能的问题,从而影响结果的可靠性,对于复杂的大型应用程序可用性不高,并且使用成本较高。针对这一问题,本申请的技术方案通过应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间,并在内存监控空间中记录内存分配信息以及内存释放信息,从而实现了监控内存的功能。

本申请的实施例提供了一种监控应用程序内存的方法,一般性的,本实施例所述的监控应用程序内存的方法由内存监控程序完成,该方法通过应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间,并在内存监控空间中记录内存分配信息以及内存释放信息,完成对内存的监控。所述监控应用程序内存的方法实施例如下:

请参考图1,其示出了根据本申请的实施例提供的监控应用程序内存的方法的流程图。

所述监控应用程序内存的方法包括:

步骤s101,应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间。

一个应用程序在开始运行之后,会根据需求的内存运行空间的大小向操作系统申请内存空间,但是,在本实施例中,所述应用程序除了向操作系统申请内存运行空间外,还会向操作系统申请内存监控空间,所述应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间,可以采用如下方式实现:应用程序在开始运行之后,所述应用程序会根据需求的内存运行空间的大小和预设大小的内存监控空间向操作系统申请内存空间,该内存空间的大小是所述应用程序需求的内存运行空间和内存监控空间的大小的总和。

例如:预设内存监控空间的大小占用n个字节,则应用程序在每次申请内存运行空间时,实际申请内存的空间可以比应用程序所需的内存运行空间多n个字节,该n个字节的内存监控空间可以用于存放记录该应用程序的内存分配信息以及内存释放信息。

需要说明的是,所述应用程序申请内存运行空间是该应用程序在运行时需要使用的内存空间,所述内存运行空间可以预先根据具体的应用场景设定的阈值来确定的,在应用程序的初始化过程中,就可以将该阈值传递进来,并按照该阈值向操作系统进行申请内存空间;所述内存监控空间用于记录该应用程序的内存分配信息以及内存释放信息。

由于所述内存监控空间是通过预设的重载函数库中的内存管理函数进行申请以及记录该应用程序的内存分配信息以及内存释放信息的,所以在所述应用程序在向操作系统进行申请预设大小的内存监控空间之前,需要将预设的内存管理函数链接进所述应用程序中。

在本实施例中,在执行步骤s101应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间的步骤之前,将预设的重载函数库链接到应用程序中。

需要说明的是,c语言中有一些函数不需要进行编译,有一些函数也可以在多个文件中使用。一般来说,可以事先对这些函数进行编译,然后将它们放置在一些特殊的目标代码文件中,这些目标代码文件就称为函数库。函数库文件中的函数可以通过连接程序与应用程序进行连接。

函数库可以有三种使用的形式:静态、导入和动态。静态链接库的代码在编 译时就已连接到应用程序中,函数和数据被编译进一个二进制文件(通常windows下扩展名为.lib,linux/unix下扩展名为.a)。在使用静态链接库的情况下,在编译链接可执行文件时,链接器从函数库中复制这些函数和数据并把它们和应用程序的其它模块组合起来创建最终的可执行文件。而导入函数库只是在程序开始运行时才载入,在编译时,只是简单地指定需要使用的库函数。动态链接库也是在程序运行时载入,但与导入函数库不同的是,使用的库函数不是在应用程序运行开始,而是在应用程序中的语句需要使用该函数时才载入在使用动态链接库的时候。在编译链接可执行文件时,动态链接库中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载,访问库中导出的函数。动态链接库可以在应用程序运行期间释放动态链接库所占用的内存,腾出空间供其它应用程序使用。由于导入函数库和动态链接库并没有在应用程序中包括库函数的内容,只是包含了对库函数的引用,因此代码的规模比较小。

在本实施例中,提供一个动态链接版本及一个静态链接版本的重载函数库,所述将预设的重载函数库链接到应用程序中,可以采用如下方式实现:若所述应用程序是采用静态链接的应用程序,则在编译时将静态链接库链接进应用程序;若所述应用程序是采用动态连接的应用程序,则在编译时将动态链接库链接进应用程序或者应用程序运行时,通过注入的方式把动态链接库注入应用程序。

需要说明的是,在编译时将静态链接库静态链接进应用程序的时候,载入代码就会把应用程序会用到的动态代码或动态代码的地址确定下来静态链接库的链接可以使用静态链接,动态链接库也可以使用这种方法链接导入库;在应用程序调用内存管理函数时通过注入的方式把动态链接库注入应用程序使用的动态链接方法并不在一开始就完成动态链接,而是直到真正调用动态链接库代码时,载入程序才计算(被调用的那部分)动态代码的逻辑地址,然后等到某个时候,应用程序又需要调用另外某块动态代码时,载入程序又去计算这部分代码的逻辑地址,所以,这种方式使程序初始化时间较短,但运行期间的性能比不上静态链接的程序。可以理解的,静态链接库和应用程序编译在一起,在任何情况下都能运行,而动态链接库是动态链接,顾名思义就是在应用程序启动的时候才会链接,所以,当操作系统上没有该动态链接库时,应用程序就会运行失败。

需要说明的是,所述预设的重载函数库中重新实现了函数库中的各种内存管 理函数,至少包括如下内存管理函数:内存分配函数、内存释放函数以及内存调整函数,在本实施例中,所述预设的重载函数库中重新实现了函数库中的各种内存管理函数,可以采用如下方式实现:对c语言函数库最基本的内存分配函数、内存调整函数等作宏定义重载,即:用自定义的同名函数系列覆盖标准c语言中的malloc等内存管理函数,增加申请以及记录内存监控空间的相关代码,用已封装后的代码替换原函数,从而实现函数的宏定义重载,以下简称重载函数,对重载后的函数库称为重载函数库。通过重载函数策略,确保了重载前后应用程序对c语言库函数的接口调用的一致性,同时也实现了在应用程序运行的过程中,重载函数库中的新内存管理函数申请内存监控空间和记录内存分配信息和内存释放信息的功能。

例如:在编码实现中,可以通过将c语言函数库提供的malloc、free、calloc以及realloc函数改造成宏函数,使之后对函数进行调用时感受不到编码上的差异。具体实施方式可以为:可以自定义new_malloc函数、new_calloc函数、new_realloc函数实现申请内存监控空间,可以自定义new_free函数实现释放内存监控空间。

下面对所述预设的重载函数库中的内存管理函数进行详细说明。

c语言函数库提供了内存分配函数malloc、内存释放函数free、内存调整函数realloc等基于内存的管理函数,负责分配可用内存以及释放用过的内存。

其中,内存分配函数malloc的作用是向操作系统申请分配指定若干个字节的内存空间,并返回类型是void*类型,void*表示未确定类型的指针。malloc不能分配的时候返回null。malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表,调用malloc函数时,它沿表寻找一个大到足以满足用户请求所需要的内存块。如果无法获得符合要求的内存块,malloc函数会返回null指针。

内存释放函数free是释放malloc(或calloc、realloc)函数给指针变量分配的内存空间的函数。free函数与malloc函数配对使用,free函数获得指向由malloc分配的内存片段的指针,释放malloc函数申请的动态内存,以便以后的程序或操作系统使用。free函数清除指向的地址,它只作清除的工作,并告诉操作系统这块地址已经被释放和清除,可以重新被分配。

内存调整函数realloc以所指地址为首址,分配若干个字节的内存,并返回 所指地址。realloc不会初始化分配到的内存块,如果所指地址为null则相当于malloc,如果分配的若干个字节的内存为null则相当于free,如果重新分配成功则返回指向被分配内存的指针,否则返回空指针null。在使用realloc函数时先判断当前的指针是否有足够的连续内存空间,如果有则扩大指向的地址,如果内存空间不够,则按照指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存空间,而后释放原来所指内存区域,同时返回新分配的内存空间的首地址。即重新分配存储器块的地址。

需要说明的是,所述预设的重载函数库中除了内存分配函数malloc、内存释放函数free、内存调整函数realloc还包括:valloc、memalign以及posix_memalign函数,由于在调用上述函数时都会在应用程序运行的过程中申请内存监控空间和记录内存分配信息和内存释放信息,上述函数的具体功能在此不再赘述。

在本实施例中,所述应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间,可以采用如下方式实现:应用程序调用所述预设的重载函数库中的内存管理函数申请内存运行空间时,所述内存管理函数在内存中额外请求预设大小的内存监控空间。所述额外请求预设大小的内存监控空间是:用于记录内存信息的大小为16字节的标签。

需要说明的是,所述标签的数据结构具体如下:

其中,allocate_or_free_marker记录的是该内存块状态,标识此内存块的状态是否为使用中,例如:若该内存块状态为allocate则说明该内存块处于已分配状态;若该内存块状态为free则说明该内存块处于释放状态。

allocate_or_free_backtrace_id记录的是当前函数调用栈的标识,通过分配函数调用栈的标识可以获得内存块最后操作的函数地址,例如:分配函数调用栈的标识可以是分配函数调用栈的id。

allocate_or_free_timestamp记录的是时间戳,例如:对申请的内存运行空间进行分配时的当前系统时间以及对申请的内存运行空间进行释放时的当前系统时间。

allocate_or_free_tid记录的是对申请的内存运行空间进行请求的线程标识以及对释放的内存空间进行请求的线程标识。

memory_bucket_id记录的是重载函数库中的内存管理函数根据申请的内存运行空间的大小,将所述内存运行空间进行分桶操作的顺序对当前内存大小对应桶设置的桶标识,记录后通过memory_bucket_id可以获取本内存块的空间信息。

memory_tracer_tag_marker记录的是用于区分在内存中额外请求预设大小的内存监控空间的标识,可以理解的,由于该标签是在内存中额外请求预设大小的内存监控空间,所以通过该标签标识可以在应用程序内存中标识以及区分该标签的位置,便于读取。

可以理解的,所述标签中记录的数据分别对应于内存分配信息和内存释放信息中的设置的内存块状态、内存分配栈标识、时间戳、线程标识、桶标识以及标签标识。

为了能在不影响应用程序运行的情况下获取完整的内存使用信息,本实施例的技术方案提供了一种优选实施方式,在优选方式下,所述对申请的内存运行空间进行分配或释放时,根据在应用程序中已经运行的进程的内存镜像信息,创建与该进程内存镜像相同的子进程。

需要说明的是,可以采用fork函数实现,根据在应用程序中已经运行的进程的资源信息(内存空间、堆、栈等资源),创建与该进程资源相同的子进程。fork函数是计算机程序设计中的分叉函数,将运行着的应用程序分成2个完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的进程。这两个进程中的进程继续执行,就像是两个用户同时启动了该应用程序的两个副本,由fork创建的新进程被称为子进程。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程id。

在所述根据在应用程序中已经运行的进程的内存镜像信息,创建与该进程内存镜像相同的子进程的步骤之后,根据与该进程内存镜像相同的子进程,获取父进程在额外请求的内存监控空间中完整记录的内存分配信息及内存释放信息。

在本实施例中,所述当应用程序发生异常时,获取当前应用程序的内存布局,可以采用如下方式实现:

调用终止函数使子进程终止运行,并转存进程信息获取应用程序的内存布局。

可以理解的,转存进程信息获取的应用程序的内存布局,实际就是父进程在额外请求的内存监控空间中记录的完整内存分配信息及内存释放信息。

需要说明的是,调用abort()函数使子进程终止运行,获取该应用程序的完整内存镜像,并在内存镜像中获取在额外请求的内存监控空间中记录的完整内存分配信息及内存释放信息,从而获得任何一个内存地址的使用状态及最后的属主信息。

可以理解的,在子进程终止运行时,该应用程序还可以在所在的父进程中正常运行。

步骤s103,对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息。

在本实施例中,所述对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息,可以采用如下方式实现:应用程序调用所述预设的重载函数库中的内存管理函数分配申请的内存运行空间,并将本次内存分配信息记录在额外请求的内存监控空间中。所述额外请求预设大小的内存监控空间是:用于记录内存信息的大小为16字节的标签。

为了使在额外请求的内存监控空间中记录的本次内存分配信息更加准确,本实施例的技术方案提供了一种优选实施方式,在优选方式下,所述对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息,具体包括步骤s103-1至s103-2,下面结合附图2作进一步说明。

请参考图2,其示出了根据本申请的实施例提供的对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息的方法的流程图。

步骤s103-1,应用程序调用所述预设的重载函数库中的内存管理函数分配申请的内存运行空间时,判断所述内存管理函数是否成功分配申请的内存运行空间。

在本实施例中,所述判断所述内存管理函数是否成功分配申请的内存运行空间,可以采用如下方式实现:判断内存分配函数malloc的返回值是否不为null,若是,则执行步骤s103-2,若是,则在所述标签中记录本次内存分配信息。

需要说明的是,内存分配函数malloc的返回类型是void*类型。当malloc函数的返回值为null时表示内存分配不成功,返回值不为null时表示分配正常,程序继续向下运行。

步骤s103-2,若是,则在所述标签中记录本次内存分配信息。

在本实施例中,若接收到内存分配函数malloc的返回值不为null的判断结果,则将本次内存分配信息记录在额外请求的内存监控空间中。

在本实施例中,所述在所述标签中记录本次内存分配信息,具体包括步骤s103-2-1至s103-2-6,下面结合附图3作进一步说明。

请参考图3,其示出了根据本申请的实施例提供的在所述标签中记录本次内存分配信息的方法的流程图。

步骤s103-2-1,将所述标签中的内存块状态设置为已分配状态。

在本实施例中,所述将所述标签中的内存块状态设置为已分配状态,可以采用如下方式实现:当malloc函数的返回值不为null时,则将所述标签中的内存块状态设置为已分配状态。

例如:将所述标签中的内存块状态设置为allocate。

步骤s103-2-2,调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的函数调用栈的标识。

需要说明的是,所述回溯函数,例如:intbacktrace(void**buffer,intsize)用于获取函数调用堆栈,将获取的信息存放在buffer中,buffer是一个指针列表,参数size用来指定buffer中可以保存多少个void*元素。函数返回值是实际获取的指针个数,最大不超过size大小,在本实施例中,通过所述回溯函数获取函数调用栈的标识,并将所述标签中的内存分配栈标识设置为通过回溯函数获取的函数调用栈的标识。

需要说明的是,分配内存块的客户或拥有者可以通过请求了内存分配和/ 或释放的应用程序的可执行代码序列或者栈的回溯来表示。在复杂的应用程序中,回溯对于更精确地识别应用程序活动的特定子集是很有用的。全局分配表中的每一个条目记录了内存分配的一条回溯路径,这些路径使用散列值进行索引。随后,在内存分配/释放过程中,更新相应回溯路径上分配/释放的内存大小。

由于backtrace操作性能较低,所以默认只会对特定的backtrace_id进行抽样调用,若全部调用则将导致大型的应用程序不能正常运行。为了解决backtrace性能问题,本实施例的技术方案提供了一种优选实施方式,在优选方式下,所述调用回溯函数获取函数调用栈的标识,可以采用编译器开关记录回溯函数获取的函数调用栈的标识,具体说,就是采用编译器开关逐层记录回溯函数所需内容以替换backtrace操作。所述采用编译器开关记录回溯函数获取的函数调用栈的标识,具体包括步骤s103-2-2-1至s103-2-2-2,下面结合附图4作进一步说明。

请参考图4,其示出了根据本申请的实施例提供的采用编译器将回溯函数注入应用程序获取函数调用栈的标识的方法的流程图。

步骤s103-2-2-1,在每个函数调用的出入口调用跟踪函数。

在本实施例中,所述在每个函数调用的出入口调用跟踪函数,可以采用如下方式实现:使用gcc(gnucompilercollection)添加-finstrument-functions编译器在编译的过程中插入相应的代码,-finstrument-functions使在每个函数调用之前调用一个名为__cyg_profile_func_enter的跟踪函数,在每个函数退出时调用一个名为__cyg_profile_func_exit的跟踪函数。

例如:在函数调用的入口调用:void__cyg_profile_func_enter(void*func_address,void*call_site);在函数调用的出口调用:void__cyg_profile_func_exit(void*func_address,void*call_site)。

由于应用程序bug造成申请的内存不足或者野指针操作会造成应用程序内存被写坏,而且内存被写坏后访问这些内存将导致应用程序行为不可预期,且触发时间和问题时间间隔可能较长,从而现场破坏,问题难于调查,为了解决内存被写坏的问题,本实施例的技术方案提供了一种优选实施方式,在优选方式下,在所述在每个函数调用的出入口调用跟踪函数的步骤之前,在所述跟踪函数中预设内存写坏的判断条件。

例如:在跟踪函数__cyg_profile_func_enter和__cyg_profile_func_exit中加入检查点,即满足内存写坏的判断条件pattern。

与在所述跟踪函数中预设内存写坏的判断条件的步骤相对应的,本实施例的技术方案提供了一种优选实施方式,在优选方式下步骤s103-2-2-1在每个函数调用的出入口调用跟踪函数之后,具体包括如下步骤:

判断内存块是否满足预设内存写坏的判断条件;

若是,则调用终止函数结束该应用程序,并转储保存进程信息;

若否,则执行所述通过栈记录所述跟踪函数调用返回地址,并通过回溯函数汇总栈信息获取调用栈的标识的步骤。

可以理解的,判断内存块是否满足预设内存写坏的判断条件的步骤是在调用__cyg_profile_func_enter和__cyg_profile_func_exit函数之后,通过在上述函数中的检查点判断当前内存块是否被写坏。

需要说明的是,所述终止函数是abort()函数,该函数的作用是异常终止一个进程,具体的,abort()函数首先解除进程对sigabrt信号的阻止,然后向调用进程发送该信号。abort()函数会导致进程的异常终止除非sigabrt信号被捕捉并且信号处理句柄没有返回。

步骤s103-2-2-2,通过栈记录所述跟踪函数调用返回地址,通过回溯函数汇总栈信息获取调用栈的标识。

在本实施例中,所述通过栈记录所述跟踪函数调用返回地址,通过回溯函数汇总栈信息获取调用栈的标识,可以采用如下方式实现:在重载函数库中定义线程局部变量,并接收在函数调用的入口调用的__cyg_profile_func_enter函数和在函数调用的出口调用的__cyg_profile_func_exit函数实时更新当前线程函数调用栈,并在线程局部变量中记录,之后通过回溯函数汇总栈信息,并获取和此分配函数调用栈匹配的标识。

需要说明的是,在所述通过栈记录所述跟踪函数调用返回地址,通过回溯函数汇总栈信息获取调用栈的标识的步骤之后,将所述标签中的内存分配栈标识设置为记录分配函数调用栈的标识。

步骤s103-2-3,获取对申请的内存运行空间进行分配时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行分配时的当前系统时间。

在本实施例中,所述获取对申请的内存运行空间进行分配时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行分配时的当前系统时间,可以采用如下方式实现:利用操作系统提供的接口获取对申请的内存运行空间进行分配时的当前系统时间,并将所述标签中的时间戳设置为获取的内存运行空间进行分配时的当前系统时间。

例如:例如,可以使用操作系统提供的gettimeofday函数实现上述获取对申请的内存运行空间进行分配时的当前系统时间的功能。

步骤s103-2-4,获取对申请的内存运行空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对申请的内存运行空间进行请求的线程标识。

在本实施例中,所述获取对申请的内存运行空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对申请的内存运行空间进行请求的线程标识,可以采用如下方式实现:当应用程序的线程对申请的内存运行空间进行请求时,会根据请求的内存大小获取符合预置条件的内存空间,分配给该线程并获取线程的标识,将所述标签中的线程标识设置为获取的对申请的内存运行空间请求内存的线程的标识。

例如:假设线程请求的内存大小是1m,则操作系统会在内存中选择同样为1m的内存空间分配给该线程,此时,操作系统选择的这1m的内存空间被称为一个内存块,当线程将这1m的内存释放之后,该内存块就成为空闲的内存空间,即该内存块可以分配给其他的线程。

步骤s103-2-5,根据申请的内存运行空间的大小,将所述内存运行空间进行分桶操作,并按照分桶操作的顺序对每个桶设置桶标识,在所述标签中的桶标识中记录当前内存大小对应桶的桶标识。

需要说明的是,所述分桶操作相当于对申请的内存运行空间进行预分配的过程,即在向操作系统申请到内存运行空间之后,首先将其划分为多个内存块,然后再将其划分为多个内存桶,也就是说,在程序进行具体的内存请求之前已经对申请到的内存空间进行了划分。当一个进程请求内存空间时,会携带有需要的内存空间大小的信息,根据请求的内存空间大小,选择符合预置条件的内存桶。例如,可以选择大于用户请求的内存大小的最小内存桶;换言之,当某进程请求内存时,意味着有数据需要存放在内存中,因此,请求的内存空间大小取决于需要存放的数据的大小。

在本实施例中,内存桶是预先划分好的,在进行内存空间分配时也是按内存桶进行分配,而进程请求的内存空间大小是不确定的。

例如,申请的内存运行空间的大小为10m,则将所述内存运行空间进行分桶操作,将该内存运行空间划分为1m,2m,3m,4m4个内存桶,并按照分桶操作的顺序对每个桶设置桶标识,即第一个1m的内存桶的桶标识为1,第二个2m的内存桶的桶标识为2,第三个3m的内存桶的桶标识为3,第四个4m的内存桶的桶标识为4,并在所述标签中的桶标识中记录每个桶的桶标识,通过桶标识就可以可以获得本内存分配块的空间信息。

步骤s103-2-6,将所述标签中的标签标识设置为已添加标签的标识。

需要说明的是,所述标签标识是用于区分在内存中额外请求预设大小的内存监控空间的标识,可以理解的,由于该标签是在内存中额外请求预设大小的内存监控空间,所以通过该标签标识可以在应用程序内存中标识以及区分该标签的位置,便于读取。例如:所述标签中的标签标识可以是“已添加标签”或者是其他能区分内存监控空间和内存运行空间的标识。

步骤s105,对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息。

在本实施例中,所述对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息,可以采用如下方式实现:对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录该申请的内存运行空间释放后的内存块状态、内存分配栈标识、时间戳、线程标识、桶标识以及标签标识。

在具体实施时,应用程序调用所述预设的重载函数库中的内存管理函数释放申请的内存运行空间时,在所述标签中记录本次内存释放信息。所述额外请求预设大小的内存监控空间是:用于记录内存信息的大小为16字节的标签。

在本实施例中,所述在所述标签中记录本次内存释放信息,具体包括步骤s105-1至s105-5,下面结合附图5作进一步说明。

请参考图5,其示出了根据本申请的实施例提供的在所述标签中记录本次内存释放信息的方法的流程图。

步骤s105-1,将所述标签中的内存块状态设置为已释放状态。

在本实施例中,所述将所述标签中的内存块状态设置为已释放状态,可以采 用如下方式实现:free函数清除malloc(或calloc、realloc)函数给指针变量分配的内存空间指向的地址后,则将所述标签中的内存块状态设置为已释放状态。

例如:将所述标签中的内存块状态设置为free。

步骤s105-2,调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的内存块的释放函数调用栈的标识。

需要说明的是,所述回溯函数,例如:intbacktrace(void**buffer,intsize)用于获取函数调用堆栈,将获取的信息存放在buffer中,buffer是一个指针列表,参数size用来指定buffer中可以保存多少个void*元素。函数返回值是实际获取的指针个数,最大不超过size大小,在本实施例中,通过所述回溯函数获取函数调用栈的标识,并将所述标签中的内存分配栈标识设置为通过回溯函数获取的函数调用栈的标识。

由于backtrace操作性能较低,所以默认只会对特定的backtrace_id进行抽样调用,若全部调用则将导致大型的应用程序不能正常运行。为了解决backtrace性能问题,本实施例的技术方案提供了一种优选实施方式,在优选方式下,所述调用回溯函数获取函数调用栈的标识,可以采用编译器将回溯函数注入应用程序获取函数调用栈的标识。所述采用编译器将回溯函数注入应用程序获取函数调用栈的标识,由于在前面实施例中已经对此进行了比较详细的描述,此处不再赘述。

步骤s105-3,获取对申请的内存运行空间进行释放时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行释放时的当前系统时间。

在本实施例中,所述获取对申请的内存运行空间进行释放时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行释放时的当前系统时间,可以采用如下方式实现:利用操作系统提供的接口获取对申请的内存运行空间进行释放时的当前系统时间,并将所述标签中的时间戳设置为获取的内存运行空间进行释放时的当前系统时间。

例如,可以使用操作系统提供的gettimeofday函数实现上述获取对申请的内存运行空间进行释放时的当前系统时间的功能。

步骤s105-4,获取对释放的内存空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对释放的内存空间进行请求的线程标识。

在本实施例中,所述获取对释放的内存空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对释放的内存空间进行请求的线程标识,可以采用如下方式实现:当应用程序的线程对释放的内存空间进行请求时,会获取对释放的内存空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对释放的内存空间进行请求的线程标识。

步骤s105-5,将所述标签中的标签标识设置为已添加标签的标识。

需要说明的是,所述标签标识是用于区分在内存中额外请求预设大小的内存监控空间的标识,可以理解的,由于该标签是在内存中额外请求预设大小的内存监控空间,所以通过该标签标识可以在应用程序内存中标识以及区分该标签的位置,便于读取。例如:所述标签中的标签标识可以是“已添加标签”或者是其他能区分内存监控空间和内存运行空间的标识。

由于在对申请的内存运行空间进行分配时,在所述标签中的内存块状态设置为已分配状态,用来表示内存被使用的开始,所以在对申请的内存运行空间进行释放之前,需要对所述标签中的内存块状态进行识别,在所述标签中记录本次内存释放信息的步骤之前,具体包括如下步骤:

判断所述标签中的内存块状态是否为已分配状态;

若是,则执行所述在所述标签中记录本次内存释放信息的步骤;

若否,则调用终止函数结束该应用程序,并转储保存进程信息。

在本实施例中,如果在所述标签中记录本次内存释放信息之前,所述标签中的内存块状态为已释放状态,则说明该内存发生内存重复释放,则调用终止函数结束该应用程序,并转储保存进程信息,禁止释放操作;如果在所述标签中记录本次内存释放信息之前,所述标签中的内存块状态为已分配状态,则说明该内存为首次释放,并执行所述在所述标签中记录本次内存释放信息的步骤。

可以理解的,在释放内存时,可能为首次或重复释放,为进行区分只需检测所述标签中的内存块状态,若所述标签中的内存块状态为已释放状态,则说明该内存发生内存重复释放;若所述标签中的内存块状态为已分配状态,则说明该内存为首次释放,可以进行释放操作。

需要说明的是,所述终止函数是abort()函数,该函数的作用是异常终止一个进程,具体的,abort()函数首先解除进程对sigabrt信号的阻止,然后向调 用进程发送该信号。abort()函数会导致进程的异常终止除非sigabrt信号被捕捉并且信号处理句柄没有返回。

在上述的实施例中,提供了一种监控应用程序内存的方法,与上述监控应用程序内存的方法相对应的,本申请还提供了一种监控应用程序内存的装置。由于装置的实施例基本相似于方法的实施例,所以描述得比较简单,相关之处参见方法实施例的部分说明即可。下述描述的装置实施例仅仅是示意性的。所述监控应用程序内存的装置实施例如下:

请参考图6,其示出了根据本申请的实施例提供的监控应用程序内存的装置的示意图。

所述监控应用程序内存的装置,包括:监控空间请求单元601、内存分配信息记录单元603以及内存释放信息记录单元605;

所述监控空间请求单元601,用于应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间;

所述内存分配信息记录单元603,用于对申请的内存运行空间进行分配时,在额外请求的内存监控空间中记录本次内存分配信息;

所述内存释放信息记录单元605,用于对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息。

可选的,所述监控应用程序内存的装置,还包括:重载函数库链接单元;

所述重载函数库链接单元,用于在所述应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间之前,将预设的重载函数库链接到应用程序中。

可选的,所述重载函数库链接单元,链接到应用程序中的至少包括如下内存管理函数:内存分配函数、内存释放函数以及内存调整函数。

可选的,所述重载函数库链接单元,包括:静态链接子单元以及动态链接子单元;

所述静态链接子单元,用于若所述应用程序是采用静态链接的应用程序,则在编译时将静态链接库链接进应用程序;

所述动态链接子单元,用于若所述应用程序是采用动态连接的应用程序,则在编译时将动态链接库链接进应用程序或者应用程序运行时,通过注入的方式把动态链接库注入应用程序。

可选的,所述监控空间请求单元601,具体用于应用程序调用所述预设的重载函数库中的内存管理函数申请内存运行空间时,所述内存管理函数在内存中额外请求预设大小的内存监控空间。

可选的,所述监控空间请求单元601,具体用于应用程序调用所述预设的重载函数库中的内存管理函数申请内存运行空间时,所述内存管理函数在内存中额外请求用于记录内存信息的大小为16字节的标签。

可选的,所述内存分配信息记录单元603,包括:判断子单元以及内存分配信息记录子单元;

所述判断子单元,用于应用程序调用所述预设的重载函数库中的内存管理函数分配申请的内存运行空间时,判断所述内存管理函数是否成功分配申请的内存运行空间;

所述内存分配信息记录子单元,用于接收所述判断子单元的判断结果,若是,则在所述标签中记录本次内存分配信息。

可选的,所述内存分配信息记录子单元,包括:已分配状态设置子单元、调用栈标识设置子单元、时间设置子单元、线程标识设置子单元、桶标识设置子单元以及标签标识设置子单元;

所述已分配状态设置子单元,用于将所述标签中的内存块状态设置为已分配状态;

所述调用栈标识设置子单元,用于调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的函数调用栈的标识;

所述时间设置子单元,用于获取对申请的内存运行空间进行分配时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行分配时的当前系统时间;

所述线程标识设置子单元,用于获取对申请的内存运行空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对申请的内存运行空间进行请求的线程标识;

所述桶标识设置子单元,用于根据申请的内存运行空间的大小,将所述内存运行空间进行分桶操作,并按照分桶操作的顺序对每个桶设置桶标识,在所述标签中的桶标识中记录当前内存大小对应桶的桶标识;

所述标签标识设置子单元,用于将所述标签中的标签标识设置为已添加标签 的标识。

可选的,所述内存释放信息记录单元605,具体用于应用程序调用所述预设的重载函数库中的内存管理函数释放申请的内存运行空间时,在所述标签中记录本次内存释放信息。

可选的,所述内存释放信息记录单元605,包括:已释放状态设置子单元、调用栈标识设置子单元、释放时间设置子单元、线程标识更新子单元以及标签标识添加子单元;

所述已释放状态设置子单元,用于将所述标签中的内存块状态设置为已释放状态;

所述调用栈标识设置子单元,用于调用回溯函数获取函数调用栈的标识,将所述标签中的内存分配栈标识设置为通过回溯函数获取的内存块的释放函数调用栈的标识;

所述释放时间设置子单元,用于获取对申请的内存运行空间进行释放时的当前系统时间,将所述标签中的时间戳设置为获取的内存运行空间进行释放时的当前系统时间;

所述线程标识更新子单元,用于获取对释放的内存空间进行请求的线程标识,将所述标签中的线程标识设置为获取的对释放的内存空间进行请求的线程标识;

所述标签标识添加子单元,用于将所述标签中的标签标识设置为已添加标签的标识。

可选的,所述调用栈标识设置子单元,具体用于采用编译器开关记录回溯函数获取的函数调用栈的标识。

可选的,所述调用栈标识设置子单元,包括:

跟踪函数调用子单元,用于在每个函数调用的出入口调用跟踪函数;

标识获取子单元,用于通过栈记录所述跟踪函数调用返回地址,并通过回溯函数汇总栈信息获取调用栈的标识。

可选的,所述监控应用程序内存的装置,还包括:状态判断单元、内存释放信息记录触发单元以及终止函数调用单元;

所述状态判断单元,用于在所述标签中记录本次内存释放信息之前,判断所述标签中的内存块状态是否为已分配状态;

所述内存释放信息记录触发单元,用于接收所述状态判断单元的判断结果,若是,则执触发所述内存释放信息记录单元;

所述终止函数调用单元,用于接收所述状态判断单元的判断结果,若否,则调用终止函数结束该应用程序,并转储保存进程信息。

可选的,所述监控应用程序内存的装置,还包括:条件设置单元、条件判断单元、终止函数调用单元以及标识接收触发单元;

所述条件设置单元,用于在所述在每个函数调用的出入口调用跟踪函数之前,在所述跟踪函数中预设内存写坏的判断条件;

所述条件判断单元,用于在所述在每个函数调用的出入口调用跟踪函数之后,判断内存块是否满足预设内存写坏的判断条件;

所述终止函数调用单元,用于接收所述条件判断单元的判断结果,若是,则调用终止函数结束该应用程序,并转储保存进程信息;

所述标识接收触发单元,用于接收所述条件判断单元的判断结果,若否,则触发所述标识接收子单元。

可选的,所述内存分配信息记录单元603,还包括:子进程创建子单元;

所述子进程创建子单元,用于在所述对申请的内存运行空间进行分配或释放时,根据在应用程序中已经运行的进程的内存镜像信息,创建与该进程资源相同的子进程。

可选的,所述监控应用程序内存的装置,还包括:内存信息获取单元;

所述内存信息获取单元,用于当应用程序发生异常时,调用终止函数使子进程终止运行,并转存进程信息获取应用程序的内存布局。

在上述的实施例中,提供了一种监控应用程序内存的方法以及一种监控应用程序内存的装置,此外,本申请还提供了一种电子设备;所述电子设备实施例如下:

请参考图7,其示出了根据本申请的实施例提供的电子设备的示意图。

所述电子设备,包括:显示器701;处理器703;存储器705;

所述存储器705,用于存储内存监控程序,所述程序在被所述处理器读取执行时,执行如下操作:应用程序申请内存运行空间时,在内存中额外请求预设大小的内存监控空间;对申请的内存运行空间进行分配时,在额外请求的内存监 控空间中记录本次内存分配信息;对申请的内存运行空间进行释放时,在额外请求的内存监控空间中记录本次内存释放信息。

在一个典型的配置中,计算设备包括一个或多个处理器(cpu)、输入/输出接口、网络接口和内存。

内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(ram)和/或非易失性内存等形式,如只读存储器(rom)或闪存(flashram)。内存是计算机可读介质的示例。

1、计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(pram)、静态随机存取存储器(sram)、动态随机存取存储器(dram)、其他类型的随机存取存储器(ram)、只读存储器(rom)、电可擦除可编程只读存储器(eeprom)、快闪记忆体或其他内存技术、只读光盘只读存储器(cd-rom)、数字多功能光盘(dvd)或其他光学存储、磁盒式磁带,磁带磁磁盘存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括非暂存电脑可读媒体(transitorymedia),如调制的数据信号和载波。

2、本领域技术人员应明白,本申请的实施例可提供为方法、系统或计算机程序产品。因此,本申请可采用完全硬件实施例、完全软件实施例或结合软件和硬件方面的实施例的形式。而且,本申请可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、cd-rom、光学存储器等)上实施的计算机程序产品的形式。

本申请虽然以较佳实施例公开如上,但其并不是用来限定本申请,任何本领域技术人员在不脱离本申请的精神和范围内,都可以做出可能的变动和修改,因此本申请的保护范围应当以本申请权利要求所界定的范围为准。

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