本申请涉及内部管理技术领域,特别是涉及一种内存回收方法、装置、存储介质和计算机设备。
背景技术:
垃圾回收(garbagecollection,gc)是一种自动内存管理机制,可以自动的查找指定内存区域中的无用对象并将其删除,从而释放内存。常用的gc算法为标记清除(mark-sweep),该算法的主要机制是在需要进行垃圾回收时,暂停目标应用的运行,遍历查找内存中仍被目标应用需要的对象并进行标记,之后将未被标记的对象作为垃圾删除。
然而,标记清除算法需要一次完成内存中全部对象的遍历,使得目标应用在较长时间内暂停运行,造成明显的“卡顿”,无法满足一些对运行流畅性要求高的场景的需求,比如游戏场景,尤其当前游戏内容越来越复杂,动态创建对象并改变对象之间引用关系的现象频繁发生。
技术实现要素:
基于此,有必要针对视频制作操作方所且笔记内容零散的技术问题,提供一种内存回收方法、装置、存储介质和计算机设备。
一种内存回收方法,包括:
当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间所述目标应用创建后未被删除的每个对象的遍历标记;
从目标顺序的对象的位置开始依次对每个所述对象是否为所述目标应用运行所必需的对象进行遍历,为遍历到的所述必需的对象添加遍历标记,当预设的单次回收时限到达或遍历完毕时暂停遍历;
当暂停遍历但尚未遍历完毕时,继续运行所述目标应用单位时长后再次暂停运行,将最后一次暂停遍历的位置确定为目标顺序的对象的位置,返回从目标顺序的对象的位置开始依次对每个对象是否为所述目标应用运行所必需的对象进行遍历的步骤;
当遍历完毕时,将截至所述当前时间目标应用创建后未被删除的无所述遍历标记的对象删除,并继续运行所述目标应用等待下一次内存回收。
一种内存回收装置,所述装置包括:
准备模块,用于当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间所述目标应用创建后未被删除的每个对象的遍历标记;
标记模块,用于从目标顺序的对象的位置开始依次对每个所述对象是否为所述目标应用运行所必需的对象进行遍历,为遍历到的所述必需的对象添加遍历标记,当预设的单次回收时限到达或遍历完毕时暂停遍历;当暂停遍历但尚未遍历完毕时,继续运行所述目标应用单位时长后再次暂停运行,将最后一次暂停遍历的位置确定为目标顺序的对象的位置,返回从目标顺序的对象的位置开始依次对每个对象是否为所述目标应用运行所必需的对象进行遍历的步骤;
删除模块,用于当遍历完毕时,将截至所述当前时间目标应用创建后未被删除的无所述遍历标记的对象删除,并继续运行所述目标应用等待下一次内存回收。
一种计算机可读存储介质,存储有计算机程序,所述计算机程序被处理器执行时,使得所述处理器执行上述内存回收方法的步骤。
一种计算机设备,包括存储器和处理器,所述存储器存储有计算机程序,所述计算机程序被所述处理器执行时,使得所述处理器执行上述内存回收方法的步骤。
上述内存回收方法、装置、计算机可读存储介质和计算机设备,在内部回收标记阶段,目标应用每运行单位时长暂停一下来完成一次标记,由此将一轮内存回收中一个大的标记任务分摊为多个小的标记任务穿插在目标应用运行过程中执行,每次小的标记任务具有对应的单次回收时限,所需时间非常短,同时这种轻便的回收机制提高了内存回收频率,大大降低了目标应用内部开销,从前端页面展示上表现为页面刷新更流畅,消除了页面“卡顿”的现象。
附图说明
图1为一个实施例中内存回收方法的应用环境图;
图2为一个实施例中内存回收方法的流程示意图;
图3为一个实施例中内存回收方法的原理示意图;
图4为一个具体实施例中遍历初始准备步骤的流程示意图;
图5为一个具体实施例中遍历对象步骤的流程示意图;
图6为一个具体实施例中查找待删除对象步骤的流程示意图;
图7为一个具体实施例中删除待删除对象步骤的流程示意图;
图8为另一个实施例中内存回收方法的原理示意图;
图9为一个实施例中内存回收装置的结构框图;
图10为另一个实施例中内存回收装置的结构框图;
图11为一个实施例中计算机设备的结构框图;
图12为一个实施例中计算机设备的结构框图。
具体实施方式
为了使本申请的目的、技术方案及优点更加清楚明白,以下结合附图及实施例,对本申请进行进一步详细说明。应当理解,此处所描述的具体实施例仅仅用以解释本申请,并不用于限定本申请。
图1为一个实施例中内存回收方法的应用环境图。该内存回收方法应用于内存回收系统。该内存回收系统包括终端110和服务器120。终端110和服务器120通过网络连接。终端110可运行有目标应用,如游戏应用、页面浏览应用、社交应用、视频应用等。服务器120是为目标应用提供服务的后台服务器。用户在终端110使用目标应用,目标应用加载本地缓存或者从服务器120拉取的数据资源,实现页面展示。终端110具体可以是台式终端或移动终端,移动终端具体可以手机、平板电脑、笔记本电脑等中的至少一种。在一些实施例中,终端110还可以是自助售货机、游戏机等设备。服务器120可以用独立的服务器或者是多个服务器组成的服务器集群来实现。
如图2所示,在一个实施例中,提供了一种内存回收方法。本实施例主要以该方法应用于计算机设备来举例说明,计算机设备具体可以是上述图1中的终端110或服务器120。参照图2,该内存回收方法具体包括如下步骤:
s202,当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间目标应用创建后未被删除的每个对象的遍历标记。
其中,内存回收条件是指启动运行gc线程的触发条件。计算机设备上运行的目标应用具有对应的应用线程和gc线程。目标应用基于应用线程运行。基于gc线程运行的gc算法用于对目标应用运行产生的内存垃圾进行回收。内存回收条件具体可以是预设的内存回收周期到达或者内存占用率达到阈值等。其中,内存回收周期是指进行内存回收的时间周期,如30秒或1分钟等,即每隔半分钟或者1分钟进行一次内存回收。内存回收周期需要根据目标应用所加载数据资源的复杂度合理设定,内存回收周期太短会使目标应用频繁被中断,内存回收周期太长会造成大量内存被持续占用,使目标应用出现卡顿甚至卡死的现象。内存占用率的阈值是预先设置的内存占用率最大值,如60%等。
在目标应用中,对象是对类的实例化。类是对所具有相同特征实体的抽象,无需占用内存,而对象则是具体的实体,需要占用内存空间。在基于java的目标应用中,可以通过关键字new创建新的对象。比如,在游戏场景中,涉及的对象可能包括虚拟场景中的建筑、花草等物件、虚拟对象以及为虚拟对象所用的手雷、手枪等装备。对象与对象之间可以互相引用。对象在创建后若长时间未使用时则会在视作垃圾被删除,以回收其占用的内存。
遍历标记是在对目标应用所创建对象进行遍历过程中为对象添加的用于表征已被遍历过的标记,具体可以是标识码,如预设的字符串。已被遍历的目标应用所必需的对象具有对应的标识码,未被遍历或已被遍历但不属于目标应用所必需的对象不具有对应的标识码,对应清除遍历标记可以是删除标识码。遍历标记还可以是状态码,如“1”表示已遍历,“0”表示未遍历等,对应清除遍历标记可以是将“1”重置为“0”。
目标应用从启动至退出可视作一次运行(包括后台运行)。目标应用在一次运行期间可能需要进行多轮内存回收。当前时间是开始本轮内存回收的时间,可以记作ti,其中i为目标应用本次运行期间进行内存回收的轮次。比如,t1表示目标应用本次运行期间第一轮内存回收。下文以本轮内存回收为第一轮内部内存回收为例进行描述。
具体地,当计算机设备实现为终端时,终端基于所运行的目标应用中的渲染引擎对本地缓存或从服务器拉取的页面资源进行渲染,展示应用页面。渲染引擎是目标应用中的一种核心组件,用于对页面资源进行渲染,具体可以是unity、ue4(unrealengine4,虚幻引擎4)等。用户可以浏览应用页面的页面内容,或对应用页面中的页面内容进行控制操作。比如,在游戏场景中,用户可以在游戏页面对虚拟对象在虚拟场景中位置、动作、采用的装备等进行交互控制。当计算机设备实现为服务器时,服务器基于所运行的目标应用中的渲染引擎对页面资源进行渲染,将渲染的页面返回至终端。
在目标应用运行期间,计算机设备监控当前是否符合内存回收条件。当仍不符合内存回收条件时,计算机设备继续运行目标应用。当符合内存回收条件时,计算机设备通过暂停应用线程来控制暂停运行目标应用,并启动gc线程开始进行内存回收。基于gc线程运行的gc算法进行内存回收的主要机制包括标记和删除两个阶段,具体是在标记阶段完成遍历标记的添加后进入删除阶段将无遍历标记的对象删除。在开始本轮内存回收时,计算机设备记录当前时间,并进行标记前的准备,即首先将上一次内存回收时为对象添加的遍历标记清除。
s204,从目标顺序的对象的位置开始依次对每个对象是否为目标应用运行所必需的对象进行遍历,为遍历到的必需的对象添加遍历标记,当预设的单次回收时限到达或遍历完毕时暂停遍历。
其中,目标应用运行所必需的对象是目标应用在当前时间t1及之后的目标时长内正常运行所依赖的对象,包括根对象(rootobject)以及根对象直接或间接引用到的对象。根对象是目标应用在当前时间t1正常运行所依赖的对象。比如,在游戏场景中,游戏应用在t1时刻所必需的对象包含全局的管理器、数据表格配置对象、当前的地图关卡对象等。根对象所指向的对象,即被根对象直接或间接应用的对象是目标应用在当前时间t1之后可能需要的对象。
如上文,gc算法的内存回收机制包括标记过程和删除过程。本申请将一轮内存回收中的标记过程分多次完成,每次完成一部分标记任务。单次回收时限则是预设的进行一次标记的最长耗时限制,如1毫秒等。换言之,实际进行一次标记所用的时间tij不超过单次回收时限。其中tij为开始目标应用本次运行期间第i轮内存回收中的第j次标记的时间。
目标顺序的对象的位置是每次标记开始进行遍历的位置。一轮内存回收需要进行多次标记,即需要进行多次遍历,从而每次标记时所指的目标顺序的对象的位置不同。当直接基于目标应用的程序代码进行遍历时,第一次遍历所对应的目标顺序的对象的位置是第一个未被删除的对象在程序代码中的位置。当前次标记对应目标顺序的对象的位置是前一次标记所暂停的位置。比如,假设待遍历的有序排列的多个对象包括a1-a10,第一次标记遍历至a3,则第二次标记对应的目标顺序的对象即为a3。
具体地,计算机设备在开始一轮内存回收时,确定目标应用运行至当前时间t1所创建的未被删除的对象,即定位目标应用在t1时刻所有的未被删除的对象。在本轮内存回收期间目标应用随时可能创建新的对象,此新的对象安排在下一轮内存回收时进行遍历。计算机设备开始本次标记,从目标顺序的对象的位置开始依次对每个对象是否属于根对象,或者被根对象直接或间接引用的对象进行遍历。若是,计算机设备为该对象添加遍历标记;反之,不添加遍历标记。
计算机设备在每一次开始标记时进行计时,在单次回收时限内基于当前cpu(centralprocessingunit,中央处理器)等处理能力对尽可能多的对象进行遍历。当单次回收时限到达且遍历数组尚未遍历完毕时,计算机设备暂停遍历。当单次回收时限尚未到达但所确定的对象均已遍历完毕时,计算机设备结束遍历,完成本次内存回收的所有标记过程。
在一个实施例中,为了提高遍历效率,计算机设备在开始一轮内存回收时,确定目标应用运行至当前时间t1所创建的未被删除的对象,可以基于所确定的对象构建一个对象序列。后续可以直接对对象序列进行遍历,而无需对程序代码逐行遍历。
s206,当暂停遍历但尚未遍历完毕时,继续运行目标应用单位时长后再次暂停运行,将最后一次暂停遍历的位置确定为目标顺序的对象的位置,返回从目标顺序的对象的位置开始依次对每个对象是否为目标应用运行所必需的对象进行遍历的步骤。
单位时长t是预先指定的目标应用为内存回收的标记阶段持续运行的时长,如30毫秒等。当目标应用为游戏应用、视频应用等需要展示视频画面时,单位时长可以是根据是视频的帧速率确定的。视频包括多个视频帧,帧速率是每秒钟刷新视频帧的帧数,如30帧/秒等。以30帧/秒的帧速率为例,若期望分帧进行标记,即每播放一帧视频帧进行一次标记,则单位时长可以是播放一帧所需要的时间33毫秒。若期望每播放连续的两帧视频帧进行一次标记,则单位时长可以是播放两帧所需要的时间66毫秒。如此类推。
具体地,若暂停遍历但尚未遍历完毕时,则计算机设备启动运行目标应用,在目标应用运行单位时长后再次暂停运行,开始下一次标记。每一次标记是在上一次停止遍历的位置继续遍历,直至最后一个对象遍历完成。也就是说,一轮内存回收事实上对待遍历的对象进行一轮完整的遍历,但该轮完整的遍历分为多次以接力的方式完成。
在一个实施例中,目标应用用于播放视频;视频包括多个视频帧;当符合内存回收条件时,暂停运行目标应用包括:当符合内存回收条件时,在当前顺序视频帧播放完毕时暂停播放视频;当暂停遍历但尚未遍历完毕时,继续运行目标应用单位时长后再次暂停运行包括:当暂停遍历但尚未遍历完毕时,继续播放下一顺序视频帧;当下一顺序视频帧播放完毕时,暂停播放视频。
在视频播放场景(如游戏场景)中分帧标记为例,目标应用暂停的时机为视频页面播放的一个视频帧加载完毕时,也就是每播放完一个视频帧暂停一下来完成一次标记,由此将一轮内存回收中一个大的标记任务分摊为多个小的标记任务穿插在视频播放过程中执行,每次小的标记任务具有对应的单次回收时限,所需时间非常短,从前端页面展示上表现为页面刷新更流畅。
s208,当遍历完毕时,将截至当前时间目标应用所创建的无遍历标记的对象删除,并继续运行目标应用等待下一次内存回收。
当在本轮内存回收开始时确定的对象全部完成遍历时,本轮内存回收的标记任务完成,可以开始执行删除任务。具体地,计算机设备重新对本轮内存回收开始时确定的待遍历对象进行新一轮的遍历,以确定其中无遍历标记的对象,将查找到的无遍历标记的对象作为无用对象删除。删除无用对象的过程也可以按照上述标记过程的逻辑分多次穿插在目标应用运行期间进行,即目标应用每运行单位时长暂停下来删除一部分无用对象,直至全部无用对象删除完毕,本轮内存回收完成。
值得注意的是,如上文,在本轮内存回收期间目标应用随时可能创建新的对象,在标记阶段,是对开始本轮内存回收那一刻定格下来的对象进行遍历,删除也只是对本轮内部回收的那一刻定格下来的无遍历标记的对象进行删除,而在此期间创建的对象此新的对象安排在下一轮内存回收时进行标记,也不会被删除。
在一个实施例中,也可以将本轮内存回收开始时确定的待遍历对象拆分为多组,基于多线程对多组待遍历对象进行同步遍历,如此可以减少每轮内存回收时标记的次数,进而减少目标应用需要暂停的次数,进一步提高目标应用运行流畅性。
上述内存回收方法,在内部回收标记阶段,目标应用每运行单位时长暂停一下来完成一次标记,由此将一轮内存回收中一个大的标记任务分摊为多个小的标记任务穿插在目标应用运行过程中执行,每次小的标记任务具有对应的单次回收时限,所需时间非常短,同时这种轻便的回收机制提高了内存回收频率,大大降低了目标应用内部开销,从前端页面展示上表现为页面刷新更流畅,消除了页面“卡顿”的现象。
在一个实施例中,上述内存回收方法还包括:基于目标应用运行所必需的对象建立遍历数组及对应的数组指针;将数组指针指向遍历数组中第一顺序的对象;从目标顺序的对象的位置开始依次对每个对象是否为目标应用运行所必需的对象进行遍历,为遍历到的必需的对象添加遍历标记包括:在预设的单次回收时限内对数组指针所指向的当前对象添加遍历标记,并在当前对象指向其他对象时将被指向的对象添加至遍历数组等待遍历;将数组指针指向遍历数组中下一对象继续遍历,直至单次回收时限到达或遍历数组遍历完毕时暂停遍历。
其中,遍历数组checkarray可以是在开始本次内存回收时创建,并在遍历过程中不断进行数组元素扩种的一种数组。在开始本次内存回收时所创建的初始的遍历数组checkarray包含记录目标应用所必需的根对象。在标记阶段,不断将根对象直接或间接引用的对象添加至遍历数组checkarray中。
数组指针itptr是与遍历数组checkarray同时定义的用于指向遍历数组的不同数组元素的指针。初始的数组指针itptr指向遍历数组checkarray中第一顺序的数组元素。当基于遍历数组进行遍历时,上述目标顺序的对象的位置是指向遍历数组中不同顺序对象的指针地址。
具体地,参考图3,图3示出了一个实施例中一轮内存回收的原理示意图。如图3所示,当符合内存回收条件时,计算机设备首先进行遍历初始准备。在遍历初始准备阶段,计算机设备主要进行遍历标记的清除和遍历数组的初始化。计算机设备基于目标应用所必需的根对象初始化遍历数组,并初始化数组指针itptr指向遍历数组的第一个数组元素。
计算机设备开始本次标记,首先检查当前对象是否已经具有遍历标记。若是,直接跳过,开始遍历下一顺序对象。若否,计算机设备为当前对象添加遍历标记,并确认当前对象是否直接或者间接应用了其他对象。若当前对象直接或间接应用了其他对象,计算机设备将当前对象所应用的对象追加至遍历数组尾部,将数组指针itptr指向遍历数组中下一顺序对象,按照上述逻辑将下一顺序对象作为当前对象继续遍历。若当前对象并未应用其他对象,计算机设备直接将数组指针itptr指向遍历数组中下一顺序对象,按照上述逻辑将下一顺序对象作为当前对象继续遍历。
本实施例中,基于遍历数组进行对象标记,可以提高对象标记效率。
在一个实施例中,基于目标应用运行所必需的对象建立遍历数组及对应的数组指针包括:获取用于记录在当前时间目标应用运行所必需的对象的根数组;初始化遍历数组,将根数组中的对象复制作为遍历数组的数组元素;初始化用于指向遍历数组中不同数组元素的数组指针。
其中,目标应用基于渲染引擎提供了两个重要的数组:用于记录目标应用在本次运行期间所创建未被删除的全部对象的全量数组allobjs,以及用于记录目标应用运行所必需的根对象的根数组rootobjs。初始的遍历数组checkarray可以通过复制根数组rootobjs得到。
值得注意的是,目标应用在运行期间不同时刻所创建的对象,以及所必需的根对象是不同的。也就是说,全量数组与根数组在不同时间所记录的数组元素是动态变化的。每轮内存回收重新创建一个为本轮所用的遍历数组checkarray。具体可以是在开始一轮内部内存回收时获取全量数组allobjs及根数组rootobjs的快照,以将全量数组allobjs及根数组rootobjs的数组元素定格在开始本轮内存回收时(即上述当前时间)的状态,通过复制根数组rootobjs快照得到初始的遍历数组checkarray。
具体地,计算机设备在开始一轮内存回收时,基于当前时间的根数组rootobjs初始化遍历数组,并初始化数组指针itptr指向遍历数组的第一个数组元素。
本实施例中,基于根数组初始化遍历数组,提高遍历数组初始化效率。
在一个实施例中,将根数组中的对象复制作为遍历数组的数组元素包括:剔除根数组中未指向其他对象的永久对象;为永久对象添加遍历标记;将剔除了永久对象的根数组中的对象添加至遍历数组。
在实际应用中,可能存在一些对象是目标应用大多数时候均需要的对象。比如,在游戏场景中,虚拟场景中的花草可能是长时间需要展示在游戏页面的,如此“花草”作为根对象,每轮内存回收均需要对其进行遍历。永久对象是目标应用长时间需要,且可以提前预知其未引用其他对象的根对象。永久对象可以是预先指定的。
具体地,为了提高遍历效率,本实施例在根据根数组初始化遍历数组时,对根数组中的永久对象进行过滤,在遍历初始准备阶段即为被过滤掉的永久对象添加上遍历标记。计算机设备只需根据过滤掉永久对象的根数组初始化遍历数组,由此可以免去对永久对象的遍历。
本实施例中,对遍历数组进行遍历一方面是为了给根对象添加遍历标记,另一方面更重要是发现根对象可能引用的对象,将被引用的对象也纳入遍历输入添加遍历标记,而对于永久对象已经可以提前预知其未引用其他对象,因而只需提前为其自身添加上遍历标记以避免删除即可。过滤永久对象可以提高遍历效率,进而提高内存回收效率。
在一个实施例中,将根数组中的对象复制作为遍历数组的数组元素包括:获取用于记录目标应用新创建的对象的临时数组;将根数组及临时数组中的对象复制作为遍历数组的数组元素;上述内存回收方法还包括:记录临时数组中对象被添加至遍历数组的次数;将被添加至遍历数组的次数达到预设值的旧对象从临时数组中删除。
实际应用中,有些对象可能并不属于根对象,但也不能删除,比如新创建或创建中的对象。为了保证新创建或创建中的对象不被删除,计算机设备还建立了用于记录目标应用在当前时间及之前指定时长内所创建对象的临时数组temprootobjs。临时数组temprootobjs中的数组元素是动态变更的,随着时间的推移符合时间规定的新创建的对象不断加入,已连续参与连续多轮内存回收的对象不断剔除。
具体地,计算机设备在遍历初始准备阶段,将根数组与临时数组中的数组元素均复制至遍历数组中,即基于根数组与临时数组初始化遍历数组。新创建的对象可能是根对象,也可能不属于根对象。新创建的根对象同时出现在根数组和临时数组中。因而,将根数组与临时数组中的数组元素初始化遍历数组时,可以优先进行数组元素的去重。
在将临时数组的数组元素添加至遍历数组参与内存回收时,对临时数组的每个数组元素被添加至遍历数组的次数,即参与内存回收的次数进行记录。对于参与内存回收的次数达到预设值的对象从临时数组中删除。预设值可以根据需求自由设定,如2等,如此可以保证temprootobjs数组中的新建对象至少在连续2轮内存回收中不被删除。
本实施例中,基于临时数组,可以保证新创建或创建中的对象在指定次数的内存回收过程中不被删除。
在一个实施例中,将被添加至遍历数组的次数达到预设值的旧对象从临时数组中删除包括:将被添加至遍历数组的次数达到预设值的对象确定为旧对象;确定旧对象是否存在直接或者间接引用的对象;当存在时,判断旧对象直接或者间接引用的对象是否加载完毕;若是,将旧对象从临时数组中删除。
在实际应用中可能存在异步加载的对象。由于遍历数组是基于开始本轮内存回收之初定格确定的待遍历对象初始化建立的,也就是说,是基于开始本轮内存回收那一刻的根数组和临时数组建立的。而真正开始内存回收之后即内存回收期间,目标应用有可能继续创建新的对象的,且该对象可能是被临时数组中的对象所直接或间接应用的对象的。如此,在内存回收期间,临时数组中的对象与其他对象的引用关系发生变化。
为了避免引用关系的变化对标记结果准确性的影响,对于临时数组中异步加载的对象,本实施例在这些对象全部加载完毕时才将其从临时数组中清除出去。具体地,对于已被添加至遍历数组的次数达到预设值的对象按照上述原则应当剔除临时数组了,但此时计算机设备将该对象确定为旧对象,进一步确认是否产生了基于该旧对象异步加载的对象,即被该旧对象直接或者间接引用的对象。当存在时,计算机设备判断旧对象直接或者间接引用的对象是否加载完毕,只要在加载完毕才将旧对象从临时数组中删除。若旧对象直接或者间接引用的对象尚未加载完毕,将旧对象保留在临时数组预备参与下一轮内存回收。
本实施例中,对于异步加载的对象,只有当它完全加载完了,即它关联的子对象也加载完了,才从temprootobjs里清除出去,提高对象删除门槛,可以有效减少对象误删。
在一个实施例中,在预设的单次回收时限内对数组指针所指向的当前对象添加遍历标记,并在当前对象指向其他对象时将被指向的对象添加至遍历数组等待遍历包括:当数组指针指向的当前对象无遍历标记时,为当前对象添加遍历标记;根据对象的引用关系信息,确定当前对象是否指向其他对象;若是,将当前对象所指向的对象添加至遍历数组中最后位置。
如图3所示,在完成遍历初始准备后,计算机设备开始对遍历数组进行遍历。对遍历数组进行遍历的阶段,计算机设备主要进行遍历标记检查、遍历标记添加和被引用对象的追加。具体地,计算机设备开始本次标记,对遍历数组中数组指针itptr所指向的当前对象进行遍历。如上文,遍历数组在遍历过程中数组元素是不断扩充的。新加入的数组元素可能是本轮内存回收已经遍历过的对象。为了避免重复遍历,计算机设备首先检查当前对象是否已经具有遍历标记。若是,直接跳过,开始遍历下一顺序对象。
在当前对象尚未具有遍历标记时,计算机设备为当前对象添加遍历标记,并确认当前对象是否直接或者间接应用了其他对象。目标应用基于渲染引擎提供了每个对象的meta信息,即引用关系信息。meta信息包含该对象与其他对象的引用关系等属性信息。计算机设备根据meta信息判断当前对象是否引用了其他对象。若是,计算机设备为当前对象添加遍历标记,并将被应用的对象追加至遍历数组尾部等待遍历,将数组指针itptr指向遍历数组中下一顺序对象。若否,计算机设备为当前对象添加遍历标记,将数组指针itptr指向遍历数组中下一顺序对象,按照上述逻辑将下一顺序对象作为当前对象继续遍历。
在一个实施例中,上述内存回收方法还包括:当数组指针指向的当前对象无遍历标记时,为当前对象添加遍历标记;确定当前对象对应的变量是否为目标类型的变量;若是,将全部目标类型的对象添加至遍历数组中最后位置。
目标类型的对象具体可以是数组类型的对象。在遍历过程中,计算机设备还将全量数组allobjs中目标类型的对象全部添加至遍历数组中进行遍历。
本实施例中,将初始遍历数组中的根对象作为引子,逐步发现目标应用运行所需的潜在对象,即根对象直接或间接引用的对象,将这些潜在对象也纳入遍历数组进行遍历,并添加遍历标记以保证不被删除,可以保证目标应用正常运行确定需要的根对象与可能需要的潜在对象均不被删除,保证内存回收时目标应用运行效果。
在一个实施例中,将当前对象所指向的对象添加至遍历数组中最后位置包括:判断当前对象与所指向的对象之间的引用关系是否属于弱引用关系;若否,将当前对象所指向的对象添加至遍历数组中最后位置。
其中,对象之间的引用关系根据可达性强度可以分为强引用和弱引用。只有弱引用的对象相比有强引用的对象拥有更短暂的生命周期,gc线程扫描目标应用的内存区域过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,均会回收弱引用的对象所占内存。
具体地,计算机设备在将当前对象所引用的对象追加至遍历数组尾部之前,对被引用对象进行过滤。计算机设备根据meta信息判断被引用对象与当前对象的引用关系是否弱引用。若是,计算机设备不再将当前对象所引用的弱引用对象添加至遍历数组;反之,将当前对象所引用的对象追加至遍历数组。
本实施例中,在将当前对象所引用的对象追加至遍历数组尾部之前,对被引用对象进行过滤,可以精准限缩遍历范围,进而提高遍历效率。
在一个实施例中,当遍历完毕时,将截至当前时间目标应用所创建的无遍历标记的对象删除包括:获取用于记录截至当前时间目标应用运行所创建的全部未被删除的对象的全量数组;当遍历完毕时,将全量数组中无遍历标记的对象确定为无用对象;将无用对象删除。
其中,无用对象是目标引用当前运行所不需要的对象,具体可以是根据遍历标记的有无来判断。根据遍历阶段对遍历数组中根对象及其所引用对象添加遍历标记的逻辑,无用对象则是无遍历标记的对象。
具体地,如图3所示,在完成遍历后,计算机设备开始查找无用对象。在查找无用对象阶段,计算机设备获取全量数组allobjs,对全量数组allobjs中每个对象是否具有遍历标记进行遍历。对于不具有遍历标记的对象,计算机设备将其判定为无用对象。在删除无用对象阶段,计算机设备将查找到的对象进行删除析构。
本实施例中,借助全量数组以及遍历标记可以快速完成无用对象的排查,相比对目标应用的程序代码进行遍历的方式,大大提高无用对象查找效率,进而提高内存回收效率。
在一个实施例中,将无用对象删除包括:确定在本轮内存回收中被确定为无用对象的对象,在之前的目标轮次内存回收中是否也被判定为无用对象;若是,将无用对象删除。
其中,“目标轮次 1”是预设的将一个对象添加至待删除队列todelobjs时该对象连续被判定为无用对象的最少次数,如2或3等。当目标轮次为0时,表示一个对象只要在一轮内存回收中被判定为无用对象即将其删除。当目标轮次为1时,表示一个对象只有在连续两轮内存回收中均被判定为无用对象才将其删除。如此类推。待删除队列todelobjs可以是在一轮内存回收的删除阶段初始化建立的用于记录确定需要删除的对象的数组。
具体地,每轮遍历筛选出的“无用对象”,会有对应的数值累加。一个对象在初次被判定为无用对象时为该对象生成一个无用计数值,并随着被判定为无用对象的次数增加,该无用计数值相应累加。计算机设备在对全量数组遍历过程中,对判定为无用对象的对象,根据该无用对象的无用计数值判断该无用对象被连续判定为无用对象的次数是否达到目标轮次 1,即再次确认该对象在之前的目标轮次内存回收中是否也被判定为无用对象。若是,计算机设备将该对象添加至待删除队列todelobjs等待删除。若否,计算机设备暂时先不将该对象添加至待删除队列todelobjs。
本实施例中,在连续目标次数内存回收中均被判定为无用对象的对象才会被删除,在提高gc频率,减少目标应用内存开销的同时,可以很好的解决分多次进行标记的过程中对象间引用关系发生变更所引起的对象误删问题,保证目标应用正常运行所需要的对象不会被误删,从而很好的兼顾目标应用的页面展示效果和运行流畅性。
在一个实施例中,将截至当前时间目标应用所创建的未被删除的无遍历标记的对象删除包括:初始化待删除队列;将截至当前时间目标应用创建后未被删除的无遍历标记的对象添加至待删除队列;根据对象的引用关系信息,对待删除队列中的对象进行排序;对待删除队列中的对象执行析构前操作及内存释放前操作;按照排序对完成析构前操作及内存释放前操作的对象执行析构操作。
如图3所示,在找到无用对象,即确定待删除队列后,将待删除队列中的无用对象删除。删除无用对象的过程也可以按照上述分多次标记的逻辑,分多次完成。每次完成一部分删除任务,从而删除无用对象阶段也具有对应的最长耗时限制(以下称为单次删除时限)。单次删除时限与单次回收时限可以相同,也可以不同。
删除无用对象的过程包括排序、析构前操作、释放前操作和虚构操作4个子过程。如上文,有些对象之间存在引用关系,该类对象在删除顺序上存在依赖关系,需要等待所依赖的另一个对象首先删除才能对该对象自身作析构。排序任务是根据对象的meta信息确定对象之间的依赖关系,进而根据对象之间的依赖关系进行排序的任务。析构前操作是在真正将无用对象删除之前对有些对象需要完成的额外分析操作,可以通过spring框架提供的predestroy函数实现。释放前操作是对有些对象在执行析构前操作基础上进一步完成的额外分析操作,可以通过spring框架提供的destroy函数实现。析构操作是真正的无用对象删除操作,释放该对象占用的内存。
同一个子过程可能分多次完成,一个单次回收时限内也可能发生两个子任务的切换。具体地,计算机设备首先执行排序任务。若一个单次删除时限内完成对待删除任务队列中全部对象的排序,则在该单次删除时限内继续对待删除任务队列中全部对象执行析构前操作。若一个单次删除时限内尚未完成删除任务,则待下一个单次删除时限内继续排序,直至完成排序切换下一子过程,如此类推,直至完成删除。
本实施例中,删除之前按照对象之间的引用关系对待删除对象进行排序,可以避免待删除对象的错删对目标应用正常运行的影响;此外,在执行完毕析构前操作和释放前操作后执行析构。
在一个具体的实施例中,本申请提供的内存回收方法具体包括以下过程:
(1)遍历初始准备
假设本轮内存回收的开始时间为t1,获取渲染引擎提供的目标应用在t1时刻的全量数组allobjs,根据全量数组allobjs将目标应用截至t1时刻创建的未删除的对象的遍历标记删除。初始化遍历数组checkarray,并将渲染引擎提供的根数组rootobjs中的数组元素放入遍历数组checkarray。初始化数组指针itptr指向遍历数组checkarray的第一个数组元素。遍历初始准备阶段的耗时t0通常较短,无需分多次或多线程处理。当然,遍历初始准备的过程也可以分多次或者多线程处理。
如图4所示,遍历初始准备的过程具体包括以下步骤:
s402,当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间目标应用创建后未被删除的每个对象的遍历标记。
s404,获取用于记录在当前时间目标应用运行所必需的对象的根数组。
s406,剔除根数组中未指向其他对象的永久对象。
s408,为永久对象添加遍历标记。
s410,获取用于记录目标应用新创建的对象的临时数组。
s412,初始化遍历数组,将剔除了永久对象的根数组中的对象以及临时数组中的对象复制作为遍历数组的数组元素。
s414,记录临时数组中对象被添加至遍历数组的次数。
s416,将被添加至遍历数组的次数达到预设值的旧对象从临时数组中删除。
s418,初始化用于指向遍历数组中不同数组元素的数组指针。
s420,将数组指针指向遍历数组中第一顺序的对象。
(2)遍历对象
目标应用在每帧视频帧更新结束时,调用gc线程的tick函数进行本次标记。若gc线程的状态正处于“遍历对象”中,则会根据单次回收实现从上次遍历停止的数组指针itptr的位置继续遍历checkarray接下来的对象,并递增itptr直至到达checkarray尾部。每次tick函数会至少遍历一个对象。通常遍历单个对象的耗时非常低,不会出现卡顿。单个对象的遍历过程包括:a、检查遍历标记,若已具有遍历标记,直接跳过该对象。b、若尚不具备遍历标记,添加遍历标记,避免后期被重复遍历。c、根据对象的meta信息,遍历对象所有的“对象指针”变量,判断是否指向了其他对象。d、若该变量指向了其他对象,其被指向的对象无遍历标记,则将被指向的对象添加至checkarray尾部。e、对于对象数组类变量,将数组类的对象也添加至checkarray尾部。
上述遍历过程在目标应用每运行单位时长暂停一下,目标应用每暂停一下执行一点遍历,直至itptr达到checkarray尾部。由于在遍历过程中,checkarray数组元素也会逐渐增多,故遍历对象的过程占据整轮内存回收的大部分时间,这也是传统gc方法卡顿的时间。而本申请将遍历对象的过程平摊达到多次完成,消除了卡顿现象。
如图5所示,遍历对象的过程具体包括以下步骤:
s502,在预设的单次回收时限内,对数组指针所指向的当前对象进行遍历。
s504,当数组指针指向的当前对象无遍历标记时,为当前对象添加遍历标记。
s506,根据对象的引用关系信息,确定当前对象是否指向其他对象。
s508,若是,判断当前对象与所指向的对象之间的引用关系是否属于弱引用关系。
s510,若不属于弱引用关系,将当前对象所指向的对象添加至遍历数组中最后位置等待遍历,直至单次回收时限到达或遍历数组遍历完毕时暂停遍历。
s512,当暂停遍历但尚未遍历完毕时,继续运行目标应用单位时长后再次暂停运行,将数组指针指向遍历数组中下一顺序的对象,返回在预设的单次回收时限内,对数组指针所指向的当前对象进行遍历的步骤。
(3)找出待删除对象
遍历结束后,被根对象直接或间接引用到的对象均会被添加上遍历标记,而全量数组allobjs里其他那些没有遍历标记的对象,即为本轮内存回收遍历下,不被需要的对象。对于本轮不被需要的对象,判断是否确信不会再使用,如果确信则加入到待删除队列todelobjs中。
在遍历对象过程中,对象之间的引用关系可能会发生改变,为了减少引用关系变更对遍历标记添加准确性的影响,本申请在实现上对对象管理进行了以下优化处理:a、在基于渲染引擎提供的统一的对象创建接口创建同步或异步的对象时,将所创建的对象放入临时数组temprootobjs,临时数组temprootobjs也会被视作与根数组rootobjs同样对待。b、默认加入临时数组temprootobjs里的对象至少会维持2个循环的对象遍历,在这段时间内总是会被当做根对象,因此不会被删除。c、对异步加载的对象,只有当其完全加载完毕,即它关联的子对象也加载完毕,才有可能从temprootobjs里清除出去。d、在对“对象变量”进行赋值时,将相关对象加入temprootobjs里
每轮内存回收所筛选出的“无用对象”,会有数值累加,只有当连续(目标轮次 1)次都被判为“无用”时,才会进入真正的todelobjs中。目标轮次 1理论上越大越安全。“连续3轮”属于经验值,理论上3轮即可认为不可能发生误删的情况。
如图6所示,查找待删除对象的过程具体包括以下步骤:
s602,当遍历完毕时,获取用于记录截至当前时间目标应用运行所创建的全部未被删除的对象的全量数组。
s604,将全量数组中无遍历标记的对象确定为无用对象。
s606,确定在本轮内存回收中被确定为无用对象的对象,在之前的目标轮次内存回收中是否也被判定为无用对象。
s608,若是,将无用对象删除。
(4)删除待删除对象
删除待删除队列todelobjs里的所有对象,可以设定“耗时限制”,分多次完成删除,确保每次耗时不超过设定值。删除过程分为四个子过程:a、对todelobjs里的对象进行排序。b、对todelobjs里的对象调用predestroy函数执行析构前操作。c、对todelobjs里的对象调用destroy函数执行释放前操作、d、对todelobjs里的对象进行删除析构操作。
如图7所示,删除待删除对象的过程具体包括以下步骤:
s702,初始化待删除队列。
s704,将截至当前时间目标应用创建后未被删除的无遍历标记的对象添加至待删除队列。
s706,根据对象的引用关系信息,对待删除队列中的对象进行排序。
s708,对待删除队列中的对象执行析构前操作及内存释放前操作。
s710,按照排序对完成析构前操作及内存释放前操作的对象执行析构操作。
假设开始本轮内存回收前删除遍历标记的准备需所需时间为t0,本轮内存回收共进行了m次标记,在完成本轮内存回收标记后对无遍历标记的对象进行析构删除所需时间为td,则本轮内存回收总共用时tx=t0 t11 t12 ... t1m td。假设预设的目标应用运行的单位时长为t,且本轮内存回收共进行了n次删除,则一轮内存回收自开始至结束的持续时间为t0 t11 t12 ... t1m td (m n)*t。
假设删除阶段也是采用分多次完成方式,且单次删除时限=单次回收时限,则td=(t1m 1) (t1m 2) … (t1m n)。假设本轮内存回收的开始时间为t1,目标应用运行的单位时长为t,则在内存回收过程不同时刻目标应用的运行状态如图8所示。根据实际测试统计,基于本申请提供的内存回收机制可以实现2-3秒钟/次的gc频率(内存回收频率),而传统方式能够实现的gc频率通常只有1分钟/次。在一轮内存结束后可能立即开始下一轮内存回收,也可能需要等待一段时间,待再次符合内存回收条件时开始下一轮内存回收。若立即开始下一轮内存回,则下一轮内存回收的开始时间t2=t1 tx。
上述内存回收方法,在内部回收标记阶段,目标应用每运行单位时长暂停一下来完成一次标记,由此将一轮内存回收中一个大的标记任务分摊为多个小的标记任务穿插在目标应用运行过程中执行,每次小的标记任务具有对应的单次回收时限,所需时间非常短,同时这种轻便的回收机制提高了内存回收频率,大大降低了目标应用内部开销,从前端页面展示上表现为页面刷新更流畅,消除了页面“卡顿”的现象。
在一个具体实施例中,本申请提供的内存回收方法可以应用于游戏场景。目前的网络游戏,通常所涉及的虚拟场景地图大,视距远,虚拟场景中具有丰富的建筑、花草等细节,虚拟对象也具有大量的服装,装备,坐骑,武功等,同时还提供非常多华丽的特效。游戏应用良好的游戏体验得益于异步streaming加载的功能,而频繁的区块地图的加载和卸载,势必造成频繁的物件创建和销毁。基于传统的gc算法,集中的一帧游戏页面加载完毕时遍历全部对象,造成明显的卡顿。而基于本申请提供的内存回收方案,由于将标记过程分散穿插在多个游戏页面之间完成,每个游戏页面只需停顿较短时间,可以让这些区块地图的装载卸载变得没有感知。同时,由于本申请提供的内存回收方案相比传统gc算法提高了gc频率几十倍,gc频率的提高可以使游戏的内存也能保持在很低的量级,可支持在基于32位windows操作系统的计算机设备上运行。
图2、4、5、6和7为一个实施例中内存回收方法的流程示意图。应该理解的是,虽图2、4、5、6和7的流程图中的各个步骤按照箭头的指示依次显示,但是这些步骤并不是必然按照箭头指示的顺序依次执行。除非本文中有明确的说明,这些步骤的执行并没有严格的顺序限制,这些步骤可以以其它的顺序执行。而且,图2、4、5、6和7中的至少一部分步骤可以包括多个子步骤或者多个阶段,这些子步骤或者阶段并不必然是在同一时刻执行完成,而是可以在不同的时刻执行,这些子步骤或者阶段的执行顺序也不必然是依次进行,而是可以与其它步骤或者其它步骤的子步骤或者阶段的至少一部分轮流或者交替地执行。
在一个实施例中,如图9所示,提供了一种内存回收装置900,该装置包括准备模块902、标记模块904和删除模块906,其中:
准备模块902,用于当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间目标应用创建后未被删除的每个对象的遍历标记。
标记模块904,用于从目标顺序的对象的位置开始依次对每个对象是否为目标应用运行所必需的对象进行遍历,为遍历到的必需的对象添加遍历标记,当预设的单次回收时限到达或遍历完毕时暂停遍历;当暂停遍历但尚未遍历完毕时,继续运行目标应用单位时长后再次暂停运行,将最后一次暂停遍历的位置确定为目标顺序的对象的位置,返回从目标顺序的对象的位置开始依次对每个对象是否为目标应用运行所必需的对象进行遍历的步骤。
删除模块906,用于当遍历完毕时,将截至当前时间目标应用创建后未被删除的无遍历标记的对象删除,并继续运行目标应用等待下一次内存回收。
在一个实施例中,准备模块902还用于基于目标应用运行所必需的对象建立遍历数组及对应的数组指针;将数组指针指向遍历数组中第一顺序的对象;标记模块904还用于在预设的单次回收时限内对数组指针所指向的当前对象添加遍历标记,并在当前对象指向其他对象时将被指向的对象添加至遍历数组等待遍历;将数组指针指向遍历数组中下一对象继续遍历,直至单次回收时限到达或遍历数组遍历完毕时暂停遍历。
在一个实施例中,准备模块902还用于获取用于记录在当前时间目标应用运行所必需的对象的根数组;初始化遍历数组,将根数组中的对象复制作为遍历数组的数组元素;初始化用于指向遍历数组中不同数组元素的数组指针。
在一个实施例中,准备模块902还用于剔除根数组中未指向其他对象的永久对象;为永久对象添加遍历标记;将剔除了永久对象的根数组中的对象添加至遍历数组。
在一个实施例中,如图10所示,标记模块904包括对象遍历模块9042,用于当数组指针指向的当前对象无遍历标记时,为当前对象添加遍历标记;根据对象的引用关系信息,确定当前对象是否指向其他对象;若是,将当前对象所指向的对象添加至遍历数组中最后位置。
在一个实施例中,对象遍历模块9042还用于判断当前对象与所指向的对象之间的引用关系是否属于弱引用关系;若否,将当前对象所指向的对象添加至遍历数组中最后位置。
在一个实施例中,准备模块902还用于获取用于记录目标应用新创建的对象的临时数组;将根数组及临时数组中的对象复制作为遍历数组的数组元素;对象遍历模块9042还用于记录临时数组中对象被添加至遍历数组的次数;将被添加至遍历数组的次数达到预设值的旧对象从临时数组中删除。
在一个实施例中,对象遍历模块9042还用于将被添加至遍历数组的次数达到预设值的对象确定为旧对象;确定旧对象是否存在直接或者间接引用的对象;当存在时,判断旧对象直接或者间接引用的对象是否加载完毕;若是,将旧对象从临时数组中删除。
在一个实施例中,目标应用用于播放视频;视频包括多个视频帧;准备模块902还用于当符合内存回收条件时,在当前顺序视频帧播放完毕时暂停播放视频;对象遍历模块9042还用于当暂停遍历但尚未遍历完毕时,继续播放下一顺序视频帧;当下一顺序视频帧播放完毕时,暂停播放视频。
在一个实施例中,如图10所示,标记模块904还包括待删除对象查找模块9044,用于获取用于记录截至当前时间目标应用运行所创建的全部未被删除的对象的全量数组;当遍历完毕时,将全量数组中无遍历标记的对象确定为无用对象;将无用对象删除。
在一个实施例中,待删除对象查找模块9044还用于确定在本轮内存回收中被确定为无用对象的对象,在之前的目标轮次内存回收中是否也被判定为无用对象;若是,将无用对象删除。
在一个实施例中,删除模块906还用于初始化待删除队列;将截至当前时间目标应用创建后未被删除的无遍历标记的对象添加至待删除队列;根据对象的引用关系信息,对待删除队列中的对象进行排序;对待删除队列中的对象执行析构前操作及内存释放前操作;按照排序对完成析构前操作及内存释放前操作的对象执行析构操作。
上述内存回收装置,在内部回收标记阶段,目标应用每运行单位时长暂停一下来完成一次标记,由此将一轮内存回收中一个大的标记任务分摊为多个小的标记任务穿插在目标应用运行过程中执行,每次小的标记任务具有对应的单次回收时限,所需时间非常短,同时这种轻便的回收机制提高了内存回收频率,大大降低了目标应用内部开销,从前端页面展示上表现为页面刷新更流畅,消除了页面“卡顿”的现象。
图11示出了一个实施例中计算机设备的内部结构图。该计算机设备具体可以是图1中的终端110。如图11所示,该计算机设备包括该计算机设备包括通过系统总线连接的处理器、存储器、网络接口、输入装置和显示屏。其中,存储器包括非易失性存储介质和内存储器。该计算机设备的非易失性存储介质存储有操作系统,还可存储有计算机程序,该计算机程序被处理器执行时,可使得处理器实现内存回收方法。该内存储器中也可储存有计算机程序,该计算机程序被处理器执行时,可使得处理器执行内存回收方法。计算机设备的显示屏可以是液晶显示屏或者电子墨水显示屏,计算机设备的输入装置可以是显示屏上覆盖的触摸层,也可以是计算机设备外壳上设置的按键、轨迹球或触控板,还可以是外接的键盘、触控板或鼠标等。
图12示出了另一个实施例中计算机设备的内部结构图。该计算机设备具体可以是图1中的服务器120。如图12所示,该计算机设备包括该计算机设备包括通过系统总线连接的处理器、存储器和网络接口。其中,存储器包括非易失性存储介质和内存储器。该计算机设备的非易失性存储介质存储有操作系统,还可存储有计算机程序,该计算机程序被处理器执行时,可使得处理器实现内存回收方法。该内存储器中也可储存有计算机程序,该计算机程序被处理器执行时,可使得处理器执行内存回收方法。
本领域技术人员可以理解,图11和图12中示出的结构,仅仅是与本申请方案相关的部分结构的框图,并不构成对本申请方案所应用于其上的计算机设备的限定,具体的计算机设备可以包括比图中所示更多或更少的部件,或者组合某些部件,或者具有不同的部件布置。
在一个实施例中,本申请提供的内存回收装置可以实现为一种计算机程序的形式,计算机程序可在如图11或图12所示的计算机设备上运行。
在一个实施例中,提供了一种计算机设备,包括存储器和处理器,存储器存储有计算机程序,计算机程序被处理器执行时,使得处理器执行上述内存回收方法的步骤。此处内存回收方法的步骤可以是上述各个实施例的内存回收方法中的步骤。
在一个实施例中,提供了一种计算机可读存储介质,存储有计算机程序,计算机程序被处理器执行时,使得处理器执行上述内存回收方法的步骤。此处内存回收方法的步骤可以是上述各个实施例的内存回收方法中的步骤。
本领域普通技术人员可以理解实现上述实施例方法中的全部或部分流程,是可以通过计算机程序来指令相关的硬件来完成,的程序可存储于一非易失性计算机可读取存储介质中,该程序在执行时,可包括如上述各方法的实施例的流程。其中,本申请所提供的各实施例中所使用的对存储器、存储、数据库或其它介质的任何引用,均可包括非易失性和/或易失性存储器。非易失性存储器可包括只读存储器(rom)、可编程rom(prom)、电可编程rom(eprom)、电可擦除可编程rom(eeprom)或闪存。易失性存储器可包括随机存取存储器(ram)或者外部高速缓冲存储器。作为说明而非局限,ram以多种形式可得,诸如静态ram(sram)、动态ram(dram)、同步dram(sdram)、双数据率sdram(ddrsdram)、增强型sdram(esdram)、同步链路(synchlink)dram(sldram)、存储器总线(rambus)直接ram(rdram)、直接存储器总线动态ram(drdram)、以及存储器总线动态ram(rdram)等。
以上实施例的各技术特征可以进行任意的组合,为使描述简洁,未对上述实施例中的各个技术特征所有可能的组合都进行描述,然而,只要这些技术特征的组合不存在矛盾,都应当认为是本说明书记载的范围。
以上实施例仅表达了本申请的几种实施方式,其描述较为具体和详细,但并不能因此而理解为对本申请专利范围的限制。应当指出的是,对于本领域的普通技术人员来说,在不脱离本申请构思的前提下,还可以做出若干变形和改进,这些都属于本申请的保护范围。因此,本申请专利的保护范围应以所附权利要求为准。
1.一种内存回收方法,包括:
当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间所述目标应用创建后未被删除的每个对象的遍历标记;
从目标顺序的对象的位置开始依次对每个所述对象是否为所述目标应用运行所必需的对象进行遍历,为遍历到的所述必需的对象添加遍历标记,当预设的单次回收时限到达或遍历完毕时暂停遍历;
当暂停遍历但尚未遍历完毕时,继续运行所述目标应用单位时长后再次暂停运行,将最后一次暂停遍历的位置确定为目标顺序的对象的位置,返回从目标顺序的对象的位置开始依次对每个对象是否为所述目标应用运行所必需的对象进行遍历的步骤;
当遍历完毕时,将截至所述当前时间目标应用创建后未被删除的无所述遍历标记的对象删除,并继续运行所述目标应用等待下一次内存回收。
2.根据权利要求1所述的方法,其特征在于,所述方法还包括:
基于所述目标应用运行所必需的对象建立遍历数组及对应的数组指针;
将所述数组指针指向所述遍历数组中第一顺序的对象;
所述从目标顺序的对象的位置开始依次对每个所述对象是否为所述目标应用运行所必需的对象进行遍历,为遍历到的所述必需的对象添加遍历标记包括:
在预设的单次回收时限内对所述数组指针所指向的当前对象添加遍历标记,并在当前对象指向其他对象时将被指向的对象添加至遍历数组等待遍历;
将所述数组指针指向遍历数组中下一对象继续遍历,直至所述单次回收时限到达或所述遍历数组遍历完毕时暂停遍历。
3.根据权利要求2所述的方法,其特征在于,所述基于所述目标应用运行所必需的对象建立遍历数组及对应的数组指针包括:
获取用于记录在当前时间所述目标应用运行所必需的对象的根数组;
初始化遍历数组,将所述根数组中的对象复制作为遍历数组的数组元素;
初始化用于指向所述遍历数组中不同数组元素的数组指针。
4.根据权利要求3所述的方法,其特征在于,所述将所述根数组中的对象复制作为遍历数组的数组元素包括:
剔除所述根数组中未指向其他对象的永久对象;
为所述永久对象添加遍历标记;
将剔除了所述永久对象的根数组中的对象添加至所述遍历数组。
5.根据权利要求2所述的方法,其特征在于,所述在预设的单次回收时限内对所述数组指针所指向的当前对象添加遍历标记,并在当前对象指向其他对象时将被指向的对象添加至遍历数组等待遍历包括:
当数组指针指向的当前对象无遍历标记时,为所述当前对象添加遍历标记;
根据所述对象的引用关系信息,确定所述当前对象是否指向其他对象;
若是,将所述当前对象所指向的对象添加至所述遍历数组中最后位置。
6.根据权利要求5所述的方法,其特征在于,所述将所述当前对象所指向的对象添加至所述遍历数组中最后位置包括:
判断所述当前对象与所指向的对象之间的引用关系是否属于弱引用关系;
若否,将所述当前对象所指向的对象添加至所述遍历数组中最后位置。
7.根据权利要求3所述的方法,其特征在于,所述将所述根数组中的对象复制作为遍历数组的数组元素包括:
获取用于记录所述目标应用新创建的对象的临时数组;
将所述根数组及所述临时数组中的对象复制作为遍历数组的数组元素;
所述方法还包括:记录所述临时数组中对象被添加至所述遍历数组的次数;
将被添加至所述遍历数组的次数达到预设值的旧对象从临时数组中删除。
8.根据权利要求7所述的方法,其特征在于,所述将被添加至所述遍历数组的次数达到预设值的旧对象从临时数组中删除包括:
将被添加至所述遍历数组的次数达到预设值的对象确定为旧对象;
确定所述旧对象是否存在直接或者间接引用的对象;
当存在时,判断所述旧对象直接或者间接引用的对象是否加载完毕;
若是,将所述旧对象从所述临时数组中删除。
9.根据权利要求1所述的方法,其特征在于,所述目标应用用于播放视频;所述视频包括多个视频帧;当符合内存回收条件时,暂停运行目标应用包括:
当符合内存回收条件时,在当前顺序视频帧播放完毕时暂停播放所述视频;
所述当暂停遍历但尚未遍历完毕时,继续运行所述目标应用单位时长后再次暂停运行包括:
当暂停遍历但尚未遍历完毕时,继续播放下一顺序视频帧;
当所述下一顺序视频帧播放完毕时,暂停播放所述视频。
10.根据权利要求2所述的方法,其特征在于,所述当遍历完毕时,将截至所述当前时间目标应用所创建的无所述遍历标记的对象删除包括:
获取用于记录截至所述当前时间目标应用运行所创建的全部未被删除的对象的全量数组;
当遍历完毕时,将所述全量数组中无所述遍历标记的对象确定为无用对象;
将所述无用对象删除。
11.根据权利要求10所述的方法,其特征在于,所述将无用对象删除包括:
确定在本轮内存回收中被确定为无用对象的对象,在之前的目标轮次内存回收中是否也被判定为无用对象;
若是,将所述无用对象删除。
12.根据权利要求1所述的方法,其特征在于,所述将截至所述当前时间目标应用所创建的未被删除的无所述遍历标记的对象删除包括:
初始化待删除队列;
将截至当前时间目标应用创建后未被删除的无遍历标记的对象添加至待删除队列;
根据所述对象的引用关系信息,对所述待删除队列中的对象进行排序;
对所述待删除队列中的对象执行析构前操作及内存释放前操作;
按照所述排序对完成析构前操作及内存释放前操作的对象执行析构操作。
13.一种内存回收装置,其特征在于,所述装置包括:
准备模块,用于当符合内存回收条件时,暂停运行目标应用,并清除截至当前时间所述目标应用创建后未被删除的每个对象的遍历标记;
标记模块,用于从目标顺序的对象的位置开始依次对每个所述对象是否为所述目标应用运行所必需的对象进行遍历,为遍历到的所述必需的对象添加遍历标记,当预设的单次回收时限到达或遍历完毕时暂停遍历;当暂停遍历但尚未遍历完毕时,继续运行所述目标应用单位时长后再次暂停运行,将最后一次暂停遍历的位置确定为目标顺序的对象的位置,返回从目标顺序的对象的位置开始依次对每个对象是否为所述目标应用运行所必需的对象进行遍历的步骤;
删除模块,用于当遍历完毕时,将截至所述当前时间目标应用创建后未被删除的无所述遍历标记的对象删除,并继续运行所述目标应用等待下一次内存回收。
14.一种计算机可读存储介质,存储有计算机程序,所述计算机程序被处理器执行时,使得所述处理器执行如权利要求1至12中任一项所述的方法的步骤。
15.一种计算机设备,包括存储器和处理器,所述存储器存储有计算机程序,所述计算机程序被所述处理器执行时,使得所述处理器执行如权利要求1至12中任一项所述的方法的步骤。
技术总结