内存泄漏分析方法及相关装置与流程

文档序号:17441831发布日期:2019-04-17 04:52阅读:154来源:国知局
内存泄漏分析方法及相关装置与流程

本发明涉及计算机技术领域,更具体的说是涉及内存泄漏分析方法及相关装置。



背景技术:

内存泄漏,也称作存储渗漏,指的是程序在运行过程中动态申请的内存空间在使用完毕后未释放,导致对象一直占据内存的现象。

内存泄漏大多是由内存循环引用导致的,虽然有arc(automaticreferencecounting,自动引用计数)内存管理机制,但两个或多个对象之间进行相互引用依然会造成内存循环引用,进而导致内存泄漏。例如,对象a创建并强引用到了对象b,对象b创建并强引用到了对象c,对象c创建并强引用到了对象b。此外,对象b和c的引用计数分别是2和1。当对象a不再使用b时,会调用release释放对对象b的所有权,因为对象c还强引用了对象b,所以对象b的引用计数为1,则对象b不会被释放。而对象b不释放,对象c的引用计数就是1,因此对象c也不会被释放。这样,对象b和对象c将一直占据,引起内存泄漏。

因此,当发现某对象有内存泄漏问题时(例如发现对象有a内存泄漏问题时),如何进行内存泄漏分析,定位与该对象相互引用的对象,是目前研究的热门。



技术实现要素:

有鉴于此,本发明实施例提供内存泄漏分析方法及相关装置,以进行内存泄漏分析,定位存在内存循环引用的对象。

为实现上述目的,本发明实施例提供如下技术方案:

一种内存泄漏分析方法,包括:

获取目标对象的强引用对象,其中,所述强引用对象为被所述目标对象强引用的对象,并且,所述目标对象至少有i个,第一个所述目标对象为监测出的、发生内存泄漏的对象,第i个所述目标对象是第i-1个所述目标对象的强引用对象,i为大于1的自然数;

构造表征对象之间强引用关系的有向图,其中,所述对象包括各所述目标对象及其强引用对象,所述有向图包括节点和有向边,不同的所述节点表征不同的所述对象,并且任一所述有向边关联的两个节点包括始点和终点,所述终点表征的对象是所述始点表征的对象的强引用对象;

遍历所述有向图中的节点,以确定所述有向图中的节点是否组成环路;

若组成环路,定位所述环路上的节点所表征的对象为存在内存循环引用的对象。

一种内存泄漏分析装置,包括:

获取单元,用于:

获取目标对象的强引用对象,其中,所述强引用对象为被所述目标对象强引用的对象,并且,所述目标对象至少有i个,第一个所述目标对象为监测出的、发生内存泄漏的对象,第i个所述目标对象是第i-1个所述目标对象的强引用对象,i为大于1的自然数;

分析单元,用于:

构造表征对象之间强引用关系的有向图,其中,所述对象包括各所述目标对象及其强引用对象,所述有向图包括节点和有向边,不同的所述节点表征不同的所述对象,并且任一所述有向边关联的两个节点包括始点和终点,所述终点表征的对象是所述始点表征的对象的强引用对象;

遍历所述有向图中的节点,以确定所述有向图中的节点是否组成环路;

若组成环路,定位所述环路上的节点所表征的对象为存在内存循环引用的对象。

一种移动终端,至少包括处理器和存储器;所述处理器通过执行所述存储器中存放的程序以及调用其他设备,执行上述的内存泄漏分析方法。

可见,在本申请实施例中,在获取目标对象的强引用对象后,会构造表征对象间的强引用关系的有向图,使用有向图进行内存泄漏分析和定位,从而定位出存在内存循环引用、引发内存泄漏的对象。

附图说明

图1为本发明实施例提供的应用场景示例图;

图2a为本发明实施例提供的移动终端的计算机架构示例图;

图2b为本发明实施例提供的内存泄漏分析装置的示例性结构图;

图3为本发明实施例提供的内存泄漏分析方法的示例性流程图;

图4a和图4b为本发明实施例提供的引用关系示意图;

图5为本发明实施例提供的有向图的示意图;

图6为本发明实施例提供的释放伪造的block对象的示意图;

图7为本发明实施例提供的block对象内部结构的示意图。

具体实施方式

一般的,移动终端的app可能会存在内存泄漏的问题。内存泄漏大多是由内存循环引用导致的。本发明提供的内存泄漏分析方法及相关装置(例如内存泄漏分析装置、移动终端),则可进行内存泄漏分析,定位存在内存循环引用的对象。

内存泄漏分析装置可以软件的形式应用于移动终端中,当以软件形式存在时,上述内存泄漏分析装置具体可为独立的app,也可作为某app或操作系统的组件。

或者,上述内存泄漏分析装置可以硬件的形式,作为移动终端的组成部分(例如具体可为移动终端的控制器/处理器)。

上述内存泄漏分析方法及相关装置适用于移动终端的开发测试环境。

图1示出了上述内存泄漏分析装置101的一种示例性应用场景:监控装置102可监测app的哪个对象发生内存泄漏,内存泄漏分析装置101则可进行内存泄漏分析,定位存在内存循环引用的对象。

图2a示出了上述移动终端的一种通用计算机系统结构。

上述计算机系统可包括总线、处理器1、存储器2、通信接口3、输入设备4和输出设备5。处理器1、存储器2、通信接口3、输入设备4和输出设备5通过总线相互连接。其中:

总线可包括一通路,在计算机系统各个挂件之间传送信息。

处理器1可以是通用处理器,例如通用中央处理器(cpu)、网络处理器(networkprocessor,简称np)、微处理器等,也可以是特定应用集成电路(application-specificintegratedcircuit,asic),或一个或多个用于控制本发明方案程序执行的集成电路。还可以是数字信号处理器(dsp)、现成可编程门阵列(fpga)或者其他可编程逻辑器件、分立门或者晶体管逻辑器件、分立硬件组件。

处理器1可包括主处理器(cpu)。

处理器1的个数可为一个或多个。

存储器2中保存有执行本发明技术方案的程序,还可以保存有操作系统和其他关键业务。具体地,程序可以包括程序代码,程序代码包括计算机操作指令。更具体的,存储器2可以包括只读存储器(read-onlymemory,rom)、可存储静态信息和指令的其他类型的静态存储设备、随机存取存储器(randomaccessmemory,ram)、可存储信息和指令的其他类型的动态存储设备、磁盘存储器、flash等等。

输入设备4可包括接收用户输入的数据和信息的装置,例如键盘、鼠标、摄像头、扫描仪、光笔、语音输入装置、触摸屏、计步器或重力感应器等。

输出设备5可包括允许输出信息给用户的装置,例如显示屏、打印机、扬声器等。

通信接口3可包括使用任何收发器一类的装置,以便与其他设备或通信网络通信,如以太网,无线接入网(ran),无线局域网(wlan)等。

处理器1通过执行存储器2中所存放的程序以及调用其他设备,可实现下述实施例提供的内存泄漏分析方法。

图2b示出了内存泄漏分析装置的一种示例结构,可包括获取单元201和分析单元202,本文后续将结合内存泄漏分析方法,对上述获取单元201和分析单元202的功能进行介绍。

获取单元201和分析单元202的功能,可由前述的处理器1执行存储器2中所存放的程序以及调用其他设备实现。

图3示出了内存泄漏分析方法的一种示例性流程。图3所示的方法应用于上述提及的领域或应用场景(例如图1)中。

上述示例性流程包括:

在301部分:获取目标对象的强引用对象;

可由前述内存泄漏分析装置102的获取单元201执行301部分。

上述强引用对象为被该目标对象强引用的对象。

具体的,在一个示例中可采用深度优先算法扫描强引用对象。扫描结束条件可包括:未扫描出目标对象的强引用对象,或者,扫描深度达到预设最大深度。

以最大深度等于3为例,请参见图4a,假定对象a-c之间的关系为:

对象a强引用了对象b,对象b强引用了对象c,对象c强引用了对象a。

那么,前述的监控装置102可监测出对象a发生了内存泄漏。则以对象a作为第一个目标对象,获取对象a的强引用对象,也即对象b;

再以对象b作为第二个目标对象,获取对象b的强引用对象,也即对象c;

再以对象c作为第三个目标对象,获取对象c的强引用对象,也即对象a。如果深度是3,那么此时就结束了这一条分支路径的扫描。

此外,如果从对象a出发还有其他分支路径,则会以类似的方法进行。

例如,请参见图4b,对象a还强引用了对象d,对象d强引用了对象e,则对该分支路径,也是从对象a开始进行扫描,直至未扫描出目标对象的强引用对象(例如对象e之后再无强引用对象),或者,扫描深度达到预设最大深度。

综上可知,在本申请实施例中,上述目标对象至少有i个(i为大于1的自然数),其中,第一个目标对象为监测出的、发生内存泄漏的对象(例如对象a),第i个目标对象是第i-1个目标对象的强引用对象(例如将对象a的强引用对象—对象b作为目标对象)。

当然,在另一个示例中,也可采用广度优先的方式扫描强引用对象,在此不作赘述。

本文后续还将介绍如何根据不同类型的对象来获取其强引用对象。

在302部分:构造表征对象之间强引用关系的有向图。

需要说明的是,本部分中的“对象”包括前述的各目标对象及其强引用对象。

具体的,有向图一般包括节点和有向边,在本申请实施例中,不同的节点表征不同的对象。

任一有向边关联有两个节点:始点和终点,在本申请实施例中,终点表征的对象是始点表征的对象的强引用对象。

以图5所示的有向图为例,图5是图4a所示对象间强引用关系的有向图。

图5中的三个节点分别表征对象a-c。连接各节点的边为有向边。

以对象a和对象b为例,对象a和对象b之间的边l1为有向边,对象a是始点,对象b是终点,对象b是对象a的强引用对象;

而以对象b和对象c为例,对象b和对象c之间的边l2为有向边,对象b是始点,对象c是终点,对象c是对象b的强引用对象。

同理,对象c和对象a之间的边l3为有向边,对象c是始点,对象a是终点,对象a是对象c的强引用对象。

在303部分:遍历上述有向图中的节点,以确定该有向图中的节点是否组成环路;

若有向图中的节点组成环路,说明存在内存循环引用。

如何确定有向图中的节点是否组成环路有多种方式。在一个示例中,可使用深度优先搜索算法遍历上述有向图来确定有向图中的节点是否组成环路;在另一个示例中,可采用有向无环图算法自动检测有向图中的节点是否组成环路。

在304部分:若组成环路,定位该环路上的节点所表征的对象为存在内存循环引用的对象。

以图5为例,对象a-c环成环路,则可定位对象a-c为存在内存循环引用的对象。

可由前述内存泄漏分析装置102的分析单元202执行302-304部分。

在定位出存在内存循环引用的对象后,后续可修改代码,来解决内存循环引用的问题。

可见,在本申请实施例中,在获取目标对象的强引用对象后,会构造表征对象间的强引用关系的有向图,使用有向图进行内存泄漏分析和定位,从而定位出存在内存循环引用、引发内存泄漏的对象。

需要说明的是,在现有技术中,当发现有内存泄漏问题时(例如发现某对象有内存泄漏问题时),需要连接到instruments工具(xcode提供的一种调试工具),人工复现泄漏场景并进行分析、定位,因此,内存泄漏分析的效率非常低下。

而在本申请实施例中,当发现有内存泄漏问题时,并不需要连接到instruments工具,可自动构造有向图,使用有向无环图算法自动检测内存循环引用,实现内存泄漏自动化分析、定位。

下面,将具体介绍如何根据不同类型的对象来获取其强引用对象。

很多移动终端的app是采用objective-c语言设计的。objective-c语言中共两大类对象:objective-c对象和block(块)对象。其中,objective-c对象是用户自定义对象,而block对象是系统内部对象,对用户是不可见的。

需要说明的是,一个objective-c对象强引用的对象可以为objective-c对象或block对象,而一个block对象强引用的对象,可以为objective-c对象或block对象。

对于上述两类对象获取其强引用对象的方式是不同的。下面将分别进行介绍。

方式一,目标对象为block对象,获取block对象的强引用对象。

block对象是系统内部对象,对用户是不可见的。因此,系统并没有提供对外接口(相应的函数或方法)来查询block对象的强引用对象。

而block对象在编译后被转换成class,通过分析内部实现及block对象释放时的特性后,可以通过黑盒技术来找出block对象持有的强引用对象。

block对象释放时有如下特性:

在释放block对象时,block对象会对其强引用对象发送释放消息(release消息)。

根据上述特性,可伪造block对象及其引用对象,并且,伪造的引用对象与真实block对象的引用对象一一对应(为方便称呼,可将伪造的引用对象称为伪造引用对象,将目标对象的引用对象称为真实引用对象);

然后,释放伪造的block对象,这样,伪造的block对象向哪个伪造引用对象发送release消息,哪个伪造引用对象就是该伪造的block对象的强引用对象。而由于伪造引用对象与真实引用对象一一对应,则可确定目标对象的强引用对象。

更具体的,收到release消息的伪造引用对象可设一个标志位,表征收到release消息。然后,遍历各伪造引用对象,将有标记位的伪造引用对象确定为目标伪造引用对象(也即,收到release消息的伪造引用对象为目标伪造引用对象)。

之后,可将目标伪造引用对象所对应的真实引用对象,确定为目标对象(真实block对象)的强引用对象。

请参见图6,假定真实block对象的引用对象包括ref1和ref2,而伪造的引用对象包括detector1(block对象的消息监测器1)和detector2(消息监测器2)。其中,detector1与ref1相对应,detector2与ref2相对应。detector1和detector2用于模拟真实的引用对象。

假定释放伪造的block对象时,detector1收到了release消息,则可确定detector1所对应的ref1,为真实block对象的强引用对象。

更具体的,伪造的block对象及其引用的对象的内存布局,与真实block对象及其引用的引用对象的内存布局相同。

仍以图6为例,detector1的偏移地址(可称为偏移地址1)与ref1的偏移地址相同,detector2的偏移地址(可称为偏移地址2)与ref2的偏移地址相同。这样,伪造的block对象及其引用的对象的内存布局,与真实block对象及其引用的引用对象的内存布局相同。

若释放伪造的block对象时,detector1收到了release消息,则可查询真实block对象的偏移地址1,从而得到ref1。

进一步的,block对象的内部结构可参见图7,其中descriptor结构的size表示block实例大小,rest表示数组,rest[1]是数组内容,保存的是block对象析构函数地址。

在伪造block对象时,可令伪造的block对象的isa指针与真实block对象的isa指针指向同一种类型的类(class),isa指针指向同一种类型的class的块对象具有相同的强引用关系。

方式二,当目标对象为objective-c对象时,获取objective-c对象的强引用对象。

在介绍获取objective-c对象的强引用对象之前,让我们先简单了解一下objective-cruntime。

objective-c语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。

这意味着objective-c不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于objective-c来说,这个运行时系统就像一个操作系统一样,让所有的工作可以正常的运行。这个运行时系统即objective-cruntime。

objective-cruntime提供了很多工具,例如,objective-cruntimeclass_getivarlayout()函数和class_getweakivarlayout()函数,来帮助用户在运行期获取一个对象的详细信息,也称作内省(introspection)。

对于一个objective-c对象,可使用objective-cruntimeclass_getivarlayout()函数获取其引用的所有对象。具体作法是,将该objective-c对象的地址输入objective-cruntimeclass_getivarlayout()函数,函数会输出该objective-c对象引用的所有对象的地址(包含强引用对象和弱引用对象)。

而使用class_getweakivarlayout()函数,可获取上述objective-c对象的弱引用对象。具体作法是,将该objective-c对象的地址输入class_getweakivarlayout()函数,函数会输出该objective-c对象引用的弱引用对象。

从引用的所有对象中去除弱引用对象,则得到该objective-c对象的强引用对象。

此外,在其他实施例中,也可采用与方式一类似的方式来获得objective-c对象的强引用对象:伪造objective-c对象,并令伪造的objective-c对象与真实objective-c对象具有相同的强引用对象,然后释放伪造的objective-c对象。这样,伪造的objective-c对象将向真实objective-c对象的强引用对象发送release消息。之后,可将收到release消息的对象确定为目标对象的强引用对象。

相关介绍请参见方式一,在此不作赘述。

方式三,获取目标对象的associated(关联)对象中被目标对象强引用的对象。

无论目标对象是objective-c对象还是block对象,通过上述两种方式,都无法找到其associated对象。

一个associated对象可为objective-c对象或block对象,一般使用关联对象为已经存在的类添加属性。

associated对象对用户是不可见的,那么,如何确定目标对象的associated对象是强引用对象还是弱引用对象呢?

某一对象的associated对象通过objc_setassociatedobject方法行添加至全局字典,通过objc_removeassociatedobjects在全局字典中删除associated对象。

更具体的,使用objc_association_retain、objc_association_retain_nonatomic存储策略添加的associated对象是被强引用的。

因此,可以用新的objc_setassociatedobject方法和objc_removeassociatedobjects方法,取代(hook)原来的objc_setassociatedobject方法和objc_removeassociatedobjects方法。

需要注意的是,原来的objc_setassociatedobject方法和objc_removeassociatedobjects方法,只负责添加或删除associated对象。

而新的objc_setassociatedobject方法和objc_removeassociatedobjects方法,在使用objc_association_retain策略(或objc_association_retain_nonatomic策略),添加(或删除)任一对象(以对象j表示任一对象)的associated对象后,还会保存(或删除)对象j的地址与对象j的associated对象的索引的强引用关系。

上述强引用关系可以引用关系表的形式存储。

这样,可通过查询引用关系表来搜索目标对象的associated对象的索引,搜索出索引所对应的associated对象也是目标对象的强引用对象。

综上,以图4b所示引用关系为例,假定对象a是objective-c对象,则可采用方式二和方式三来确定对象a的强引用对象(假定对象b是采用方式二确定出的,而对象d是通过方式三确定出的)。

之后,分别以对象b和对象d作为第二个目标对象,获取对象b和对象d的强引用对象。

以对象b为例,若对象b是objective-c对象,则可采用方式二和方式三来确定其强引用对象,若对象b是block对象,则可采用方式一和方式三来确定其强引用对象;

对于其他对象也是如此,在此不作赘述。

此外,本申请还可支持后面配置监控对象过滤(例如,限制监控对象为自定义对象,将系统对象过滤掉)、监控策略(监控策略用于监控是否发生内存泄漏)等,以此提供监控灵活性及风险控制。

另外,云端可配置监控开关来启动/关闭监控策略或内存泄漏分析。

此外,云端也可配置需监控的对象的类别,或者不需监控的对象的类别。

此外,本申请的技术方案,还可与自动化工具结合。自动化工具可在测试环境下,在app运行时,模拟对移动终端的手势操作(例如点击),从而主动令app暴露内存泄漏的对象。

在监控到内存泄漏的对象后,可使用本申请提供的技术方案进行内存泄漏分析。

专业人员可以意识到,结合本文中所公开的实施例描述的各示例的单元及算法步骤,能够以电子硬件、计算机软件或者二者的结合来实现,为了清楚地说明硬件和软件的可互换性,在上述说明中已经按照功能一般性地描述了各示例的组成及步骤。这些功能究竟以硬件还是软件方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本发明的范围。

结合本文中所公开的实施例描述的方法或算法的步骤可以直接用硬件、处理器执行的软件模块,或者二者的结合来实施。软件模块可以置于随机存储器(ram)、内存、只读存储器(rom)、电可编程rom、电可擦除可编程rom、寄存器、硬盘、可移动磁盘、wd-rom、或技术领域内所公知的任意其它形式的存储介质中。

对所公开的实施例的上述说明,使本领域专业技术人员能够实现或使用本发明。对这些实施例的多种修改对本领域的专业技术人员来说将是显而易见的,本文中所定义的一般原理可以在不脱离本发明的精神或范围的情况下,在其它实施例中实现。因此,本发明将不会被限制于本文所示的这些实施例,而是要符合与本文所公开的原理和新颖特点相一致的最宽的范围。

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