首页 > 专利 > 杭州电子科技大学 > 一种基于模式的Python代码内存泄漏检测方法专利详情

一种基于模式的Python代码内存泄漏检测方法   0    0

有效专利 查看PDF
专利申请流程有哪些步骤?
专利申请流程图
申请
申请号:指国家知识产权局受理一件专利申请时给予该专利申请的一个标示号码。唯一性原则。
申请日:提出专利申请之日。
2021-05-27
申请公布
申请公布指发明专利申请经初步审查合格后,自申请日(或优先权日)起18个月期满时的公布或根据申请人的请求提前进行的公布。
申请公布号:专利申请过程中,在尚未取得专利授权之前,国家专利局《专利公报》公开专利时的编号。
申请公布日:申请公开的日期,即在专利公报上予以公开的日期。
2021-10-08
授权
授权指对发明专利申请经实质审查没有发现驳回理由,授予发明专利权;或对实用新型或外观设计专利申请经初步审查没有发现驳回理由,授予实用新型专利权或外观设计专利权。
2022-02-18
预估到期
发明专利权的期限为二十年,实用新型专利权期限为十年,外观设计专利权期限为十五年,均自申请日起计算。专利届满后法律终止保护。
2041-05-27
基本信息
有效性 有效专利 专利类型 发明专利
申请号 CN202110586274.3 申请日 2021-05-27
公开/公告号 CN113407442B 公开/公告日 2022-02-18
授权日 2022-02-18 预估到期日 2041-05-27
申请年 2021年 公开/公告年 2022年
缴费截止日
分类号 G06F11/36 主分类号 G06F11/36
是否联合申请 独立申请 文献类型号 B
独权数量 1 从权数量 5
权利要求数量 6 非专利引证数量 0
引用专利数量 2 被引证专利数量 0
非专利引证
引用专利 CN101017458A、CN105912381A 被引证专利
专利权维持 1 专利申请国编码 CN
专利事件 事务标签 公开、实质审查、授权
申请人信息
申请人 第一申请人
专利权人 杭州电子科技大学 当前专利权人 杭州电子科技大学
发明人 陈洁、姜涛、俞东进、胡海洋 第一发明人 陈洁
地址 浙江省杭州市下沙高教园区 邮编 310018
申请人数量 1 发明人数量 4
申请人所在省 浙江省 申请人所在市 浙江省杭州市
代理人信息
代理机构
专利代理机构是经省专利管理局审核,国家知识产权局批准设立,可以接受委托人的委托,在委托权限范围内以委托人的名义办理专利申请或其他专利事务的服务机构。
杭州君度专利代理事务所 代理人
专利代理师是代理他人进行专利申请和办理其他专利事务,取得一定资格的人。
杨舟涛
摘要
本发明公开了一种基于模式的Python代码内存泄漏检测方法。该方法借助类型推断来获取Python代码的类型信息,并结合自定义的模式进行内存泄漏检测,得到造成内存泄漏的循环引用。这种检测方法有精度高、速度快等特点,能有效地在代码运行之前检测出代码中存在的内存泄漏,及时通报相关开发人员采取相应的解决方案。区别于以往的检测方法仅对代码运行时内存使用情况进行分析的特点,本方法提出的一种基于模式的Python代码内存泄漏检测方法适用于软件开发过程中的编码阶段的检测,有助于尽早发现缺陷代码。
  • 摘要附图
    一种基于模式的Python代码内存泄漏检测方法
  • 说明书附图:图1
    一种基于模式的Python代码内存泄漏检测方法
法律状态
序号 法律状态公告日 法律状态 法律状态信息
1 2022-02-18 授权
2 2021-10-08 实质审查的生效 IPC(主分类): G06F 11/36 专利申请号: 202110586274.3 申请日: 2021.05.27
3 2021-09-17 公开
权利要求
权利要求书是申请文件最核心的部分,是申请人向国家申请保护他的发明创造及划定保护范围的文件。
1.一种基于模式的Python代码内存泄漏检测方法,其特征在于,包括以下步骤:
S1、输入项目的源代码,遍历项目中的所有代码文件,加载每一个Python代码文件 利用Python标准库中的ast模块得到每一个Python代码文件 对应的抽象语法树S2、利用抽象解释器技术基于步骤S1获得的抽象语法树 进行类型推断,得到类型树其中类型树 中的节点表示抽象类型,节点之间的关系表示从属关系;
S3、遍历步骤S2获得的类型树 中的每个实例类型i,获取每个实例类型i在类型树中的所有子节点,然后使用预定义的内存泄漏模式检查每个子节点b是否存在内存泄漏,如果满足其中一个内存泄漏模式,则记录引起内存泄漏的循环引用,每一个循环引用记录为一个节点序列[v0,v1,...vn],其中节点序列中的每个节点vi为类型树中的节点,相邻的节点之间存在引用关系,并且满足v0=vn;
步骤S2中通过类型推断得到类型树的具体步骤如下:
S21、根据Python定义的类型,封装若干个抽象类型;
S22、对于每个Python代码文件 对应的抽象语法树 使用抽象解释器进行类型推断得到类型树 类型树 中的每个节点表示一种抽象类型且抽象语法树 对应的模块类型加入到类型树T中作为根节点,节点之间的关系表示从属关系即子节点的定义在父节点内;
S23、依次遍历类型树 中的每个函数类型的节点,得到所有函数类型;针对每一个函数类型,判断该函数类型是否在类型推断中存在调用,即有没有至少一个调用类型所调用的函数类型是该函数类型;如果有,则跳过继续对下一个函数类型进行判断,如果没有,则将其视为新产生的函数类型并创建一个调用类型,以未知类型作为传入参数,使用抽象解释器调用一次新创建的调用类型。

2.根据权利要求1所述的一种基于模式的Python代码内存泄漏检测方法,其特征在于,步骤S21中封装的抽象类型包括以下11种:
1)模块类型:mod,其中id表示模块的唯一标识符;
2)函数类型:fun,其中id表示函数的唯一标识符;
3)调用类型:invoke,其中fun表示该调用的函数类型,[τ]表示该调用需要的参数的类型,τ表示该调用的返回值的类型;
4)类类型:cls,其中id表示类的唯一标识符,[cls]表示该类的父类的类型;
5)实例类型:ins,其中cls表示该实例所属的类类型;
6)方法类型:meth,其中fun表示函数类型,ins表示该方法所属的实例类型;
7)组合类型:任意类型的集合;
8)字典类型:dict<τ,τ>,其中两个τ分别表示字典中的健和值的类型;
9)列表类型:list<τ>,其中τ表示列表中的元素的类型;
10)元组类型:tuple<τ>,其中τ表示元组中的元素的类型;
11)集合类型:set<τ>,其中τ表示集合中的元素的类型。

3.根据权利要求1所述的一种基于模式的Python代码内存泄漏检测方法,其特征在于,步骤S3中使用预定义的内存泄漏模式检查每个子节点b是否存在内存泄漏的具体步骤如下:
S31、预定义模式1为自引用造成的内存泄漏,判断子节点b是否满足模式1,如果b与i相同,则认为满足模式1,此时记录引起内存泄漏的循环引用为[i];
S32、预定义模式2为一个实例与容器之间的循环引用造成的内存泄漏,判断子节点b是否满足模式2,如果b严格包含i,则认为满足模式2,此时记录引起内存泄漏的循环引用为[b,i];
S33、预定义模式3为一个实例与方法之间的循环引用造成的内存泄漏,判断是否满足模式3,判断步骤如S331和S332:
S331、如果子节点b属于方法类型,则检查b所属的实例类型b.ins,如果b.ins与i相同,则认为满足模式3,此时记录引起内存泄漏的循环引用为[b.ins,i];
S332、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个方法类型的t,其所属的实例类型t.ins与i相同,则认为满足模式3,此时记录引起内存泄漏的循环引用为[t.ins,i];
S34、预定义模式4为两个实例之间的循环引用造成的内存泄漏,判断子节点b是否满足模式4,判断步骤如S341和S342:
S341、如果子节点b属于实例类型,并且b与i不相同,则检查b的每个子节点,如果存在一个子节点c是实例类型并且与i等价,则认为满足模式4,此时记录引起内存泄漏的循环引用为[c,i];
S342、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个t属于实例类型,则进一步检查t内的每个子节点c,如果存在一个子节点c是实例类型并且与i等价,则认为满足模式4,此时记录引起内存泄漏的循环引用为[c,i];
S35、预定义模式5为两个实例与容器之间的循环引用造成的内存泄漏,判断子节点b是否满足模式5,判断步骤如S351和S352:
S351、如果子节点b属于实例类型,并且b与i不相同,则进一步检查b内的每个子节点,如果存在一个子节点c是实例类型并且包含i,则认为满足模式5,此时记录引起内存泄漏的循环引用为[c,i];
S352、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个t属于实例类型,则进一步检查t内的每个子节点c,如果存在一个子节点c是实例类型并且包含i,则认为满足模式5,此时记录引起内存泄漏的循环引用为[c,i];
S
36.预定义模式6为两个实例与方法之间的循环引用造成的内存泄漏,判断子节点b是否满足模式6,判断步骤如下:
如果子节点b属于实例类型,则进一步检查b的每个子节点c,如果存在一个子节点c是方法类型并且其所属的实例类型c.ins与i相同,则认为满足模式6,此时记录引起内存泄漏的循环引用为[c.ins,i]。

4.根据权利要求1所述的一种基于模式的Python代码内存泄漏检测方法,其特征在于,步骤S32中对于任意两个类型x和y,两者之间的严格包含关系判断步骤如下:
1)如果x属于字典类型,则检查x的健或值是否与y等价,如果是则认为类型x包含类型y;
2)如果x属于集合类型、列表类型或元祖类型,则检查y是否属于x中的一项,如果是则认为类型x包含类型y;
3)如果x属于组合类型,则检查x中是否存在一个类型t包含类型y,如果是则认为类型x包含类型y。

5.根据权利要求1所述的一种基于模式的Python代码内存泄漏检测方法,其特征在于,步骤S34中,对于任意两个类型x和y,两者之间的等价关系判断步骤如下:
1)如果x不属于组合类型,则判断x和y是否相同,如果相同则认为x和y等价;
2)如果x属于组合类型,则检查x中是否存在一个类型t与y等价,如果存在则认为x和y等价。

6.根据权利要求1所述的一种基于模式的Python代码内存泄漏检测方法,其特征在于,步骤S35中,对于任意两个类型x和y,两者之间的包含关系判断步骤如下:
1)如果x属于字典类型,则检查x的健或值是否与y相同,如果相同则认为类型x包含类型y;
2)如果x属于集合类型、列表类型或元祖类型,则检查y是否属于x,如果是则认为类型x包含类型y;
3)如果x属于组合类型,则检查x中是否存在一个类型t包含类型y,如果存在则认为类型x包含类型y。
说明书

技术领域

[0001] 本发明涉及软件技术领域,尤其涉及一种基于模式的Python代码内存泄漏检测方法。

背景技术

[0002] 内存泄漏是软件工程中常见的错误,即程序动态申请内存后,没有在其结束使用前释放内存,造成的内存资源长期被占用的情况。在项目早期,内存泄漏通常没有任何明显症状。内存泄漏的发生是一个连续不断的过程,随着其在系统中累积,泄漏对象的数量会不断增加,导致系统中的内存资源不断减少。当系统中的内存资源耗尽时,系统中的应用程序会暂时挂起,等待内存的重新分配。如果内存重新分配过程需要很长时间,它将导致系统崩溃。
[0003] 近年来,编程语言采用垃圾回收机制等动态内存管理机制来帮助程序员防止泄漏缺陷的发生。但是,垃圾回收机制是通过对运行时的分析来处理内存泄漏的,它需要对程序进行检测、监视或测试。同时,需要有足够多的测试用例以保证测试过程中能够触发引起内存泄漏的代码。另一方面,研究人员也采用一些静态分析的方法进行内存泄漏的检测。静态分析方法静态分析将内存泄漏检测看成为一个可达性分析问题,可以在不实际运行程序的情况检测内存泄漏。但是,对于Python来说,代码不存在显式的内存分配和释放语句,因此静态地确定对象的可访问性的成本会非常昂贵。

发明内容

[0004] 为了克服上述现有技术的不足,提出了一种基于模式的Python代码内存泄漏检测方法。本发明使用代码模式来解决内存泄漏的检测问题,可有效解决上述问题。本发明具体采用的技术方案如下:
[0005] 一种基于模式的Python代码内存泄漏检测方法,其包括以下步骤:
[0006] S1、输入项目的源代码,遍历项目中的所有代码文件,加载每一个Python代码文件利用Python标准库中的ast模块得到每一个Python代码文件 对应的抽象语法树[0007] S2、利用抽象解释器技术基于步骤S1获得的抽象语法树 进行类型推断,得到类型树 其中类型树 中的节点表示抽象类型,节点之间的关系表示从属关系;
[0008] S3、遍历步骤S2获得的类型树 中的每个实例类型 获取每个实例类型 在类型树中的所有子节点,然后使用预定义的内存泄漏模式检查每个子节点b是否存在内存泄漏,如果满足其中一个内存泄漏模式,则记录引起内存泄漏的循环引用,每一个循环引用记录为一个节点序列[v0,v1,...vn],其中节点序列中的每个节点vi为类型树中的节点,相邻的节点之间存在引用关系,并且满足v0=vn。
[0009] 作为优选,步骤S2中通过类型推断得到类型树的具体步骤如下:
[0010] S21、根据Python定义的类型,封装若干个抽象类型;
[0011] S22、对于每个Python代码文件 对应的抽象语法树 使用抽象解释器进行类型推断得到类型树 类型树 中的每个节点表示一种抽象类型且抽象语法树 对应的模块类型加入到类型树T中作为根节点,节点之间的关系表示从属关系即子节点的定义在父节点内;
[0012] S23、依次遍历类型树 中的每个函数类型的节点,得到所有函数类型;针对每一个函数类型,判断该函数类型是否在类型推断中存在调用,即有没有至少一个调用类型所调用的函数类型是该函数类型;如果有,则跳过继续对下一个函数类型进行判断,如果没有,则将其视为新产生的函数类型并创建一个调用类型,以未知类型作为传入参数,使用抽象解释器调用一次新创建的调用类型。
[0013] 作为优选,步骤S21中封装的抽象类型包括以下11种:
[0014] 1)模块类型:mod,其中id表示模块的唯一标识符;
[0015] 2)函数类型:fun,其中id表示函数的唯一标识符;
[0016] 3)调用类型:invoke,其中fun表示该调用的函数类型,[τ]表示该调用需要的参数的类型,τ表示该调用的返回值的类型;
[0017] 4)类类型:cls,其中id表示类的唯一标识符,[cls]表示该类的父类的类型;
[0018] 5)实例类型:ins,其中cls表示该实例所属的类类型;
[0019] 6)方法类型:meth,其中fun表示函数类型,ins表示该方法所属的实例类型;
[0020] 7)组合类型:任意类型的集合;
[0021] 8)字典类型:dict<τ,τ>,其中两个τ分别表示字典中的健和值的类型;
[0022] 9)列表类型:list<τ>,其中τ表示列表中的元素的类型;
[0023] 10)元组类型:tuple<τ>,其中τ表示元组中的元素的类型;
[0024] 11)集合类型:set<τ>,其中τ表示集合中的元素的类型。
[0025] 作为优选,步骤S3中使用预定义的内存泄漏模式检查每个子节点b是否存在内存泄漏的具体步骤如下:
[0026] S31、预定义模式1为自引用造成的内存泄漏,判断子节点b是否满足模式1,如果b与 相同,则认为满足模式1,此时记录引起内存泄漏的循环引用为
[0027] S32、预定义模式2为一个实例与容器之间的循环引用造成的内存泄漏,判断子节点b是否满足模式2,如果b严格包含 则认为满足模式2,此时记录引起内存泄漏的循环引用为
[0028] S33、预定义模式3为一个实例与方法之间的循环引用造成的内存泄漏,判断是否满足模式3,判断步骤如S331和S332:
[0029] S331、如果子节点b属于方法类型,则检查b所属的实例类型b.ins,如果b.ins与相同,则认为满足模式3,此时记录引起内存泄漏的循环引用为
[0030] S332、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个方法类型的t,其所属的实例类型t.ins与 相同,则认为满足模式3,此时记录引起内存泄漏的循环引用为
[0031] S34、预定义模式4为两个实例之间的循环引用造成的内存泄漏,判断子节点b是否满足模式4,判断步骤如S341和S342:
[0032] S341、如果子节点b属于实例类型,并且b与 不相同,则检查b的每个子节点,如果存在一个子节点c是实例类型并且与 等价,则认为满足模式4,此时记录引起内存泄漏的循环引用为
[0033] S342、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个t属于实例类型,则进一步检查t内的每个子节点c,如果存在一个子节点c是实例类型并且与等价,则认为满足模式4,此时记录引起内存泄漏的循环引用为
[0034] S35、预定义模式5为两个实例与容器之间的循环引用造成的内存泄漏,判断子节点b是否满足模式5,判断步骤如S351和S352:
[0035] S351、如果子节点b属于实例类型,并且b与 不相同,则进一步检查b内的每个子节点,如果存在一个子节点c是实例类型并且包含 则认为满足模式5,此时记录引起内存泄漏的循环引用为
[0036] S352、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个t属于实例类型,则进一步检查t内的每个子节点c,如果存在一个子节点c是实例类型并且包含则认为满足模式5,此时记录引起内存泄漏的循环引用为
[0037] S36.预定义模式6为两个实例与方法之间的循环引用造成的内存泄漏,判断子节点b是否满足模式6,判断步骤如下:
[0038] 如果子节点b属于实例类型,则进一步检查b的每个子节点c,如果存在一个子节点c是方法类型并且其所属的实例类型c.ins与 相同,则认为满足模式6,此时记录引起内存泄漏的循环引用为
[0039] 作为优选,步骤S32中对于任意两个类型x和y,两者之间的严格包含关系判断步骤如下:
[0040] 1)如果x属于字典类型,则检查x的健或值是否与y等价,如果是则认为类型x包含类型y;
[0041] 2)如果x属于集合类型、列表类型或元祖类型,则检查y是否属于x中的一项,如果是则认为类型x包含类型y;
[0042] 3)如果x属于组合类型,则检查x中是否存在一个类型t包含类型y,如果是则认为类型x包含类型y。
[0043] 作为优选,步骤S34中,对于任意两个类型x和y,两者之间的等价关系判断步骤如下:
[0044] 1)如果x不属于组合类型,则判断x和y是否相同,如果相同则认为x和y等价;
[0045] 2)如果x属于组合类型,则检查x中是否存在一个类型t与y等价,如果存在则认为x和y等价。
[0046] 作为优选,步骤S35中,对于任意两个类型x和y,两者之间的包含关系判断步骤如下:
[0047] 1)如果x属于字典类型,则检查x的健或值是否与y相同,如果相同则认为类型x包含类型y。
[0048] 2)如果x属于集合类型、列表类型或元祖类型,则检查y是否属于x,如果是则认为类型x包含类型y。
[0049] 3)如果x属于组合类型,则检查x中是否存在一个类型t包含类型y,如果存在则认为类型x包含类型y。
[0050] 本发明使用抽象解释器来进行类型推断,并在类型树的基础上采用基于模式的检测方法来检测代码中的内存泄漏,本法明具有如下收益:1、利用类型推断来获取代码的类型信息,使得内存泄漏检测适用于动态语言如Python;2、使用基于模式的内存泄漏检测方法,使得内存泄漏具有准确率高、速度快的特点。

实施方案

[0052] 为了使本发明的目的、技术方案及优点更加清楚明白,以下结合附图对本发明进行进一步详细说明。
[0053] 相反,本发明涵盖任何由权利要求定义的在本发明的精髓和范围上做的替代、修改、等效方法以及方案。进一步,为了使公众对本发明有更好的了解,在下文对本发明的细节描述中,详尽描述了一些特定的细节部分。对本领域技术人员来说没有这些细节部分的描述也可以完全理解本发明。
[0054] 如图1所示,本发明的一种基于模式的Python代码内存泄漏检测方法,包括以下步骤:
[0055] S1、代码提取:输入项目的源代码,遍历项目中的所有代码文件,加载每一个Python代码文件 利用Python标准库中的ast模块相应函数得到每一个Python代码文件对应的抽象语法树
[0056] S2、类型解析:利用抽象解释器技术基于步骤S1获得的抽象语法树 进行类型推断,得到类型树 其中类型树 中的节点表示抽象类型,节点之间的关系表示从属关系。
[0057] 在本实施例中,利用抽象解释器技术基于步骤S1获得的抽象语法树 进行类型推断得到类型树的具体步骤如下:
[0058] S21、根据Python定义的类型,封装若干个抽象类型;
[0059] 本实施例中,封装的抽象类型包括以下11种:
[0060] 1)模块类型:mod,其中id表示模块的唯一标识符;
[0061] 2)函数类型:fun,其中id表示函数的唯一标识符;
[0062] 3)调用类型:invoke,其中fun表示该调用的函数类型,[τ]表示该调用需要的参数的类型,τ表示该调用的返回值的类型;
[0063] 4)类类型:cls,其中id表示类的唯一标识符,[cls]表示该类的父类的类型;
[0064] 5)实例类型:ins,其中cls表示该实例所属的类类型;
[0065] 6)方法类型:meth,其中fun表示函数类型,ins表示该方法所属的实例类型;
[0066] 7)组合类型:任意类型的集合,即多个抽象类型的集合;
[0067] 8)字典类型:dict<τ,τ>,其中两个τ分别表示字典中的健和值的类型;
[0068] 9)列表类型:list<τ>,其中τ表示列表中的元素的类型;
[0069] 10)元组类型:tuple<τ>,其中τ表示元组中的元素的类型;
[0070] 11)集合类型:set<τ>,其中τ表示集合中的元素的类型。
[0071] S22、对于每个Python代码文件 对应的抽象语法树 使用抽象解释器进行类型推断得到类型树 类型树 中的每个节点表示一种抽象类型,节点之间的关系表示从属关系即子节点的定义在父节点内,而且抽象语法树 对应的模块类型加入到类型树T中作为根节点
[0072] S23、依次遍历类型树 中的每个函数类型的节点,得到所有函数类型;针对所有函数类型中的每一个函数类型,判断该函数类型是否在类型推断中存在调用,即有没有至少一个调用类型所调用的函数类型是该函数类型;如果有,则跳过继续对下一个函数类型进行判断,如果没有,则将其视为新产生的函数类型并创建一个调用类型,以未知类型作为传入参数,使用抽象解释器调用一次新创建的调用类型。
[0073] S3、内存泄漏检测:遍历步骤S2获得的类型树 中的每个实例类型 获取每个实例类型 在类型树中的所有子节点,然后使用预定义的内存泄漏模式检查每个子节点b是否存在内存泄漏,如果满足其中一个内存泄漏模式,则记录引起内存泄漏的循环引用,每一个循环引用记录为一个节点序列[v0,v1,...vn],其中节点序列中的每个节点vi为类型树中的节点,相邻的节点之间存在引用关系,并且满足v0=vn。
[0074] 本实施例中,使用预定义的内存泄漏模式检查每个子节点b是否存在内存泄漏的具体步骤如下:
[0075] S31、预定义模式1为自引用造成的内存泄漏,判断子节点b是否满足模式1,如果b与 相同,则认为满足模式1,此时记录引起内存泄漏的循环引用为
[0076] S32、预定义模式2为一个实例与容器之间的循环引用造成的内存泄漏,判断子节点b是否满足模式2,如果b严格包含 则认为满足模式2,此时记录引起内存泄漏的循环引用为
[0077] 其中,判断b是否严格包含 时,需要设定两者之间严格包含关系的判断规则。由于b和 均代表了一种抽象类型,因此本实施例中对于任意两个抽象类型x和y,两者之间的严格包含关系判断步骤如下:
[0078] 1)如果x属于字典类型,则检查x的健或值是否与y等价,如果是则认为类型x包含类型y;
[0079] 2)如果x属于集合类型、列表类型或元祖类型,则检查y是否属于x中的一项,如果是则认为类型x包含类型y;
[0080] 3)如果x属于组合类型,则检查x中是否存在一个类型t包含类型y,如果是则认为类型x包含类型y。
[0081] S33、预定义模式3为一个实例与方法之间的循环引用造成的内存泄漏,判断是否满足模式3,判断步骤如S331和S332:
[0082] S331、如果子节点b属于方法类型,则检查b所属的实例类型b.ins,如果b.ins与相同,则认为满足模式3,此时记录引起内存泄漏的循环引用为
[0083] S332、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个方法类型的t,其所属的实例类型t.ins与 相同,则认为满足模式3,此时记录引起内存泄漏的循环引用为
[0084] S34、预定义模式4为两个实例之间的循环引用造成的内存泄漏,判断子节点b是否满足模式4,判断步骤如S341和S342:
[0085] S341、如果子节点b属于实例类型,并且b与 不相同,则检查b的每个子节点,如果存在一个子节点c是实例类型并且与 等价,则认为满足模式4,此时记录引起内存泄漏的循环引用为
[0086] S342、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个t属于实例类型,则进一步检查t内的每个子节点c,如果存在一个子节点c是实例类型并且与等价,则认为满足模式4,此时记录引起内存泄漏的循环引用为
[0087] 其中,判断c与 是否等价时,需要设定两者之间等价关系的判断规则。由于c和 均代表了一种抽象类型,因此本实施例中对于任意两个抽象类型x和y,两者之间的等价关系判断步骤如下:
[0088] 1)如果x不属于组合类型,则判断x和y是否相同,如果相同则认为x和y等价;
[0089] 2)如果x属于组合类型,则检查x中是否存在一个类型t与y等价,如果存在则认为x和y等价。
[0090] S35、预定义模式5为两个实例与容器之间的循环引用造成的内存泄漏,判断子节点b是否满足模式5,判断步骤如S351和S352:
[0091] S351、如果子节点b属于实例类型,并且b与 不相同,则进一步检查b内的每个子节点,如果存在一个子节点c是实例类型并且包含 则认为满足模式5,此时记录引起内存泄漏的循环引用为
[0092] S352、如果子节点b属于组合类型,则检查b中包含的每个类型t,如果存在一个t属于实例类型,则进一步检查t内的每个子节点c,如果存在一个子节点c是实例类型并且包含则认为满足模式5,此时记录引起内存泄漏的循环引用为
[0093] 其中,判断c是否包含 时,需要设定两者之间包含关系的判断规则。由于c和 均代表了一种抽象类型,因此本实施例中对于任意两个类型x和y,两者之间的包含关系判断步骤如下:
[0094] 1)如果x属于字典类型,则检查x的健或值是否与y相同,如果相同则认为类型x包含类型y。
[0095] 2)如果x属于集合类型、列表类型或元祖类型,则检查y是否属于x,如果是则认为类型x包含类型y。
[0096] S36.预定义模式6为两个实例与方法之间的循环引用造成的内存泄漏,判断子节点b是否满足模式6,判断步骤如下:
[0097] 如果子节点b属于实例类型,则进一步检查b的每个子节点c,如果存在一个子节点c是方法类型并且其所属的实例类型c.ins与 相同,则认为满足模式6,此时记录引起内存泄漏的循环引用为
[0098] 3)如果x属于组合类型,则检查x中是否存在一个类型t包含类型y,如果存在则认为类型x包含类型y。
[0099] 上述S31~S36定义了6中不同的内存泄漏模式,每个子节点b只要符合任意一种模式就视为存在内存泄漏,若不符合任意一种模式则视为不存在内存泄漏。通过上述S1~S3的做法,就可以实现Python代码的内存泄漏检测,并定位得到造成内存泄漏的循环引用,最终可以得到所有导致内存泄漏的循环引用集合。该方法适用于软件开发过程中的编码阶段的检测,能有效地在代码运行之前检测出代码中存在的内存泄漏,及时通报相关开发人员采取相应的解决方案。
[0100] 下面将上述S1~S3应用于一个具体实施例中,以展示其技术效果。
[0101] 实施例
[0102] 本实施例步骤与具体实施方式相同,在此不再进行赘述。下面就部分实施过程和实施结果进行展示:
[0103] 数据源获取:本实施例所用的代码是从GitHub开源社区获得的4个真实开源项目的源代码。由于项目未保存有关真实内存泄漏的信息,因此有必要运行每个项目的测试用例以收集运行过程中产生的内存泄漏信息,其中每个项目的相关统计信息见表1。然后,将收集到的引起内存泄漏进行人工分类,分为符合本发明技术方案中的6种模式。
[0104] 结果验证:本实施例将实际代码运行过程中收集到的引起内存泄漏的循环引用集合与将本发明技术方案应用于项目源代码所检测得到的可能引起内存泄漏的循环引用集合做比较,以评价其方案的有效性。为了验证本发明技术方案的技术效果,选取四个指标来衡量检测的性能:
[0105] SP:用本发明技术方案找到的并且在实际运行中存在的循环引用的个数。
[0106] SN:用本发明技术方案找到的并且在实际运行中不存在的循环引用的个数。
[0107] DP:实际运行中存在的并且用本发明技术方案找到的循环引用的个数。
[0108] DN:实际运行中存在的并且用本发明技术方案不能找到的循环引用的个数。
[0109] 为了计算上述四个指标,需要判断用本发明技术方案找到的一个可能引起内存泄漏的循环引用Si是否与实际运行中收集到的一个引起内存泄漏的循环引用Di相同。假设本实施例将实际代码运行过程中收集到的引起实际内存泄漏的循环引用集合为D={D1,D2,...,Dn}。将本发明技术方案应用于项目源代码所检测得到的可能引起内存泄漏的循环引用集合为S={S1,S2,...,Sm}。假设Si=[s1,s2,...,sk]与Di=[d1,d2,...,dk]分别为包含k个类型且属于同一模式的循环引用,如果存在一个常量l(0≤l
[0110] (1)si与dj相同;
[0111] (2)如果dj与si相同,那么dj与si的子类型也相同
[0112] 表2展示了在4个数据集上使用本发明技术方案进行内存泄漏检测的到的结果与实际代码运行所收集的内存泄漏进行的比较。由表中可以看到,4个项目的DN都为0,这证明了本发明提出的基于模式的内存泄漏检测方法的有效性,即在这4个项目中本发明技术方案可以找到所有实际运行出现的内存泄漏。另外,对于boto、djblets和libNeuroML三个项目,由表可见,本发明方法分别找出了3、3和6个实际代码运行中不存在的循环引用,通过人工校验,以上12个为实际运行中没有收集到的但是真实存在的内存泄漏。这是因为代码运行所收集到的内存泄漏依赖于测试用例,在测试用例不足时,很难收集到所有的内存泄漏。而本发明技术方案属于静态分析,不依赖于测试用例。从总体上看,SP比DP大,这说明本发明方法的准确率高,除了实际运行收集到的内存泄漏外,还能够找到因为测试用例无法覆盖到而在实际运行中没能收集到的内存泄漏。
[0113] 表1 4个真实项目的实际运行得到内存泄漏数据集的统计信息表
[0114]
[0115] 表2本发明方法检测结果和实际代码运行收集的结果的对比
[0116]项目名称 SP SN DP DN
boto 315 3 274 0
djblets 26 3 25 0
libNeuroML 256 6 63 0
pymtl 56 0 37 0
[0117] 以上所述的实施例只是本发明的一种较佳的方案,然其并非用以限制本发明。有关技术领域的普通技术人员,在不脱离本发明的精神和范围的情况下,还可以做出各种变化和变型。因此凡采取等同替换或等效变换的方式所获得的技术方案,均落在本发明的保护范围内。

附图说明

[0051] 图1为本发明方法的流程图。
版权所有:盲专网 ©2023 zlpt.xyz  蜀ICP备2023003576号