具体实施方式
为使本申请的目的、技术方案和优点更加清楚,下面将结合本申请具体实施例及相应的附图对本申请技术方案进行清楚、完整地描述。显然,所描述的实施例仅是本申请一部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本申请保护的范围。
以下结合附图,详细说明本申请各实施例提供的技术方案。
本申请实施例提供的资源回收方法的执行主体,可以但不限于为手机、平板电脑、个人电脑(Personal Computer,PC)、智能电视以及任何可以运行应用的终端设备中的至少一种。此外,该方法的执行主体还可以是服务器,比如,web应用服务器,等等。
为便于描述,下文以该方法的执行主体为个人电脑为例,对该方法的实施方式进行介绍。可以理解,该方法的执行主体为个人电脑只是一种示例性的说明,并不应理解为对该方法的限定。
本申请实施例提供了一种资源回收方法,用以解决现有技术在对应用进行热部署升级时产生的资源泄露问题。该方法的具体实现流程示意图如图2所示,可以包括下述步骤:
步骤11,针对部署在容器中的应用,在运行所述容器的虚拟机中创建所述应用对应的租户,以使所述应用使用所述租户在所述虚拟机中的资源运行;
其中,所述应用可以使根据JAVA语言编写的JAVA应用,也可以是根据C/C++语言编写的应用,或者也还可以是根据PHP语言编写的应用,等等。本申请实施例对应用所使用的编程语言不做限定,为例便于描述,本申请可以以根据JAVA语言编写的JAVA应用为例进行介绍。
一般地,安装在终端上的应用在运行时,往往需要在终端上为该应用预先设置运行环境(比如预先编写代码以管理对象关系),则在终端上安装不同应用时,均需要为该应用设置运行环境,该过程较为繁琐,因而现有技术提供了一种用于部署应用的容器,该容器中预先设置有应用的运行环境,应用可以直接部署在该容器中进行运行,例如,一般可以把JAVA应用部署在JAVA容器上。
需要说明的是,这里所说的部署,是指首次将应用安装到该应用对应的容器中,与后文所述的对应用进行热部署升级并不相同。
同时,由于编写应用所使用的程序语言可能与该应用期望运行的平台所使用的程序语言不相同,例如,使用JAVA语言编写的JAVA应用,为了能够在不同平台上运行,往往需要编译成不同的目标代码。为了避免在不同平台上运行应用时,需要对应用进行重新编码,我们引入了虚拟机,通过虚拟机可以屏蔽与运行平台相关的信息,进而使得应用只需生成在虚拟机上运行的目标代码,就可以在多种平台上不加修改地运行。例如,在运行JAVA应用时所使用的JAVA虚拟机(JAVA Virtual Machine,JVM)。
一般地,在同一个容器中往往可以部署多个应用,而这些应用在运行时所需的资源均保存在运行该容器的虚拟机上,应用可以通过容器来调用虚拟机中的相关资源来运行。然而,目前由于容器对虚拟机是不透明的,即在应用通过容器调用虚拟机中的资源进行运行时,虚拟机仅可以确定是该容器对虚拟机中资源的调用,而无法确定此次调用时容器中哪个应用发起的,这也就造成无法确定容器中的应用在运行时使用了虚拟机中的哪些资源,进而在对该应用进行热部署升级时,由于无法确定该应用在虚拟机中所使用的资源,因而无法对该应用使用的资源进行回收。
例如,如图3所示,在容器中部署了应用a、应用b以及应用c三个应用,容器运行在虚拟机上,在运行过程中,应用a使用了虚拟机中的资源a,应用b使用了虚拟机中的资源b,应用c使用了虚拟机中的资源c,然而虚拟机仅能确定容器使用了该些资源,则在对应用c进行热部署升级后,由于无法确定应用c使用了虚拟机中的哪些资源,因而无法对应用c使用的虚拟机资源进行回收。
为了避免上述问题,在应用部署到容器中时,便可以通过容器在该容器运行的虚拟机中创建一个与该应用对应的租户(为了便于描述,后文称为用户租户),后续该应用可以使用对应的用户租户在虚拟机中的资源运行,进而当需要对应用使用的资源进行回收时,仅需要在虚拟机中对与该应用对应的用户租户中的资源进行回收即可。
在一种实施方式中,步骤11的具体实现方式可以包括:通过所述容器,在所述虚拟机中创建与所述应用对应的租户上下文,其中,所述租户上下文用于表征所述租户。
需要说明的是,在运行容器的虚拟机中,除了包含与容器中部署的应用对应的用户租户以外,还包括根租户,根租户用于向虚拟机中与应用对应的用户租户运行所述应用提供所需的部分或者全部资源,比如,根租户中可以包括虚拟机中的公共线程池以及虚拟机中的共享变量对象,等等。如图4所示,反映了虚拟机中根租户与用户租户之间的关系。
还需要说明的是,这里所说的运行应用所需的资源,可以包括但不仅限于以下三种:
1、线程;
其中,应用运行时使用的虚拟机中的线程,可以包括:由虚拟机中根租户的线程切换得到的线程;和/或该应用自身创建的线程。
而虚拟机中根租户的线程一般可以是指根租户中公共线程池中的线程,当应用在运行时需要使用虚拟机中根租户的线程时,往往需要将根租户中的线程切换到与该应用对应的用户租户中执行,则在一种实施方式中,将虚拟机中根租户中的线程切换到用户租户中,以实现应用使用根租户中的线程,本申请实施例提供的方法具体可以包括:通过所述容器,将所述虚拟机根租户的线程切换到所述应用对应的租户上下文中运行。
当应用需要使用虚拟机中根租户中的线程时,可以通过容器调用应用程序编程接口(Application Programming Interface,API),将虚拟机中根租户的线程切换到与该应用对应的用户租户上下文中,进而在该应用的用户租户上下文中运行由根租户的线程切换得到的线程。
2、共享变量对象;
共享变量对象实际上是程序名称暴露在公共区间里、且所有代码都可以被直接引用的变量。虚拟机中的共享变量对象只存在于根租户的内存空间里,但是被它指向的对象可以既存在于根租户内存,也可以存在于用户租户中。
3、文件句柄(file handle,FD)。
应用在运行过程中,可能需要从文件或者日志中读取数据,在从文件中读取数据时,应用首先需要调用系统函数,并向系统函数输入需要打开文件的唯一标识,进而可以通过系统函数打开文件读取数据,其中所述文件的唯一标识即文件句柄。一般地,当应用对文件的数据读取完毕后,可以再次调用系统函数关闭文件,并关闭文件句柄。
而假设应用在运行过程,通过热部署升级了,此时部署在容器中的应用被删除了,而该应用在读取文件过程中,在虚拟机中打开的文件句柄仍然未关闭,因而在对应用热部署升级后,需要对应用在虚拟机中打开的文件句柄关闭,具体的,如何关闭应用在虚拟机中打开的文件句柄,详见下文相关描述,此处不再赘述。
步骤12,在对所述应用进行热部署升级时,根据所述应用对应的租户,对所述应用使用的所述资源进行回收。
一般地,在对容器中部署的应用进行版本升级后,往往可以对运行该容器的虚拟机进行重启,以释放旧版本应用运行时使用的虚拟机资源。然而,采用热部署的方式进行应用版本升级时,可以不重启运行容器的虚拟机,因而可能造成应用在运行时使用的虚拟机资源无法被释放,即存在资源泄露问题。
为了避免应用热部署升级时产生的资源泄露问题,本申请实施例中,在对应用进行热部署升级时,可以根据该应用在的虚拟机中对应的租户,对该应用在虚拟机中使用的资源进行回收。
由于应用在运行时使用的资源一般可以包括:应用使用的虚拟机中的线程、应用打开的虚拟机中的文件句柄以及应用使用的虚拟机中的共享变量对象,因而下文从如何回收应用使用的线程,如何回收应用打开的文件句柄,以及如何回收应用使用的共享变量对象三个方面,来具体介绍本申请实施例是如何对应用使用的资源进行回收的。
a、对所述应用使用的所述虚拟机中的线程进行回收;
在对应用使用的虚拟机中的线程进行回收时,我们可以利用异常处理机制。
当在正在执行的线程中抛出异常对象后,根据异常处理机制,会查询该异常对象所对应的异常类型,并在查询到与该异常对象对应的异常类型后,该异常对象跳转到与该异常类型的处理逻辑中执行,以达到对异常对象进行处理的目的;而当根据异常处理机制未查询到抛出异常对象对应的异常类型时,将会中断该线程栈中正在执行的栈帧中的方法,并将该栈帧的方法退出线程栈,同时会将该异常对象抛至当前栈帧的调用者。
例如,如图5所示,为某个正在执行线程的线程栈,该线程栈中有栈底至栈顶依次为方法A、方法B、方法C以及方法D,其中方法A为方法B的调用者,方法B为方法C的调用者,方法C为方法D的调用者,当向该线程抛出异常对象后,假设未查询到抛出异常对象对应的异常类型,则线程栈中正在执行的方法D将会被中断,并将方法D退出该线程栈(退栈),同时会将该异常类型抛至方法D的调用者方法C,并根据异常处理机制在方法C中查询与该异常对象对应的异常类型,当查询到与该异常对应的异常类型时,将方法C退出该线程栈,并将该异常对象抛至方法B,依此类推,直至查找到与该异常对象对应的异常类型,或者将该线程栈中的方法全部退出线程栈。
则在一种实施方式中,根据异常处理机制对应用使用的线程进行回收,具体可以包括:根据所述应用对应的租户,将所述租户中运行的线程,确定为所述应用使用的虚拟机中的线程;针对所述应用使用的虚拟机中的线程抛出异常对象;根据异常处理机制,对抛出异常对象的线程进行关闭。
其中,当应用使用的线程为该应用自身创建的线程时,针对该线程进行回收,一般可以是指关闭该线程,并释放该线程所占用的资源。即在对应用自身创建的线程进行回收时,可以退栈该线程栈中的所有方法,以达到关闭该线程,并回收该线程所占用的资源的目的。
为了达到将应用自身创建的线程关闭,并释放该线程占用的资源的目的,在一种实施方式中,可以针对应用自身创建的线程抛出异常对象,并修改应用自身创建的线程的异常处理机制,以使得根据所述异常处理机制无法查询到与抛出异常对象对应的异常类型,进而根据异常处理机制,关闭应用创建的线程,具体的,本申请实施例提供的方法可以包括:对所述应用自身创建的线程进行标记;针对携带有所述标记的线程抛出异常对象;修改携带有标记的线程栈上所有方法的异常处理机制,以使得根据所述异常处理机制无法查询到与所述抛出异常对象对应的异常类型;根据异常处理机制,对所述抛出异常对象的线程进行退栈。
由于修改了应用自身创建的线程的异常处理机制,因而在该线程中抛出的异常对象将始终无法查询到对应的异常类型,根据异常处理机制,该线程栈中的方法将被依次退出线程栈,进而达到关闭线程,并回收线程所占用的资源的目的。
而当应用使用的线程为由根租户的线程切换得到的线程时,由于根租户的线程一般为公共线程,因而在针对该线程进行回收时,不能关闭该线程,而需要结束执行该线程,并将由根租户的线程切换得到的线程返回根租户的上下文中。在对由根租户的线程切换得到的线程进行回收时,可以退栈该线程栈中用户租户的方法,并将该线程栈中由根租户的线程切换得到的方法退回根租户的上下文中,以达到将由根租户的线程切换得到的线程退回根租户的上下文中的目的。
为了达到上述目的,在一种实施方式中,本申请实施例提供的方法可以包括:针对由根租户的线程切换得到的线程抛出异常对象;修改由根租户的线程切换得到的线程的异常处理机制,以使得根据所述异常处理机制无法查询到与所述抛出异常对象对应的异常类型;对所述由根租户的线程切换得到的线程中、表示应用对应的租户入口的方法进行标记,以使得携带有所述标记的方法中存的异常对象能够被异常处理机制捕捉;根据异常处理机制,对携带有所述标记的方法中存的异常对象进行抓取,并将所述方法表示的线程切换回所述根租户的上下文中。
例如,如图6所示,为某个正在执行线程的线程栈,该线程为由根租户的线程切换到用户租户中执行的,其中,方法1以及方法2为由根租户中切换到用户租户中执行的根租户中线程的方法,而方法a~方法d为该线程在用户租户中执行的方法,则在对该线程进行回收时,需要将方法a~方法d退出该线程栈。采用本申请实施例提供的方法,可以对方法2进行标记,针对该线程抛出异常对象,并修改该线程的异常处理机制,以使得根据所述异常处理机制无法查询到与所述抛出异常对象对应的异常类型,则根据异常处理机制,方法a~方法d将依次退出该线程栈,并将该异常对象抛至方法2,而方法2被预先进行了标记,因而方法2中的异常对象能够被捕捉,并跳转到异常处理逻辑中进行处理,进而不会将方法2以及方法1退出线程栈,并可以将方法2以及方法1退回至根租户的上下文中,以达到回收根租户切换得到的线程的目的。
b、对所述应用使用的所述虚拟机中的共享变量对象进行回收;
目前,在应用使用虚拟机中的共享变量对象时,需要将虚拟机根租户中的共享变量对象引用至与该应用对应的用户租户中运行,而由于用户租户对根租户中共享变量对象的引用为强引用,因而导致根据垃圾回收机制,无法对用户租户引用的共享变量对象进行回收。
为了可以对应用使用的虚拟机中的共享变量对象进行回收,即对用户租户引用的根租户中的共享变量对象进行回收,首先需要消除存在的强引用关系,在一种实施方式中,当应用被部署到容器中,且通过容器在虚拟机中创建了与该应用对应的用户租户后,可以对虚拟机中的共享变量对象进行复制,并将复制得到的共享变量对象副本保存到与所述应用对应租户的存储空间,后续当该应用需要使用虚拟机中的共享变量对象时,可以直接引用保存在该存储空间中的共享变量对象副本,从而不需要对根租户中的共享变量数据进行引用,进而消除了根租户共享变量对象与用户租户对象之间存在的强引用关系,具体的,本申请实施例提供的方法可以包括:当所述应用使用所述虚拟机中的共享变量对象时,对所述共享变量对象进行复制,获得所述共享变量对象的副本;将所述共享变量对象的副本保存到与所述应用对应租户的存储空间,以使得所述应用运行时使用保存在所述存储空间中的共享变量对象副本。
则在上述情况下,在对应用使用的虚拟机中的共享变量对象进行回收时,本申请实施例提供的方法具体可以包括:根据所述应用对应的租户,将与所述租户关联保存的共享变量对象副本,确定为所述应用使用的虚拟机中的共享变量对象;删除保存在所述存储空间中的共享变量对象副本,并回收保存所述共享变量对象副本的存储空间。
由于在这种情况下,应用使用的均为保存在与该应用对应的用户租户的存储空间中的共享变量对象副本,此时该应用在使用共享变量对象副本时不会对虚拟机中的共享变量对象造成影响,因而当需要对应用使用的共享变量对象进行回收时,仅需要删除保存在与应用对应的用户租户存储空间中的共享变量对象副本,并将回收该存储空间即可。
c、对应用打开的虚拟机中的文件句柄进行回收;
需要说明的是,在对应用打开的虚拟机中的文件句柄进行回收前,首先需要追踪应用的文件句柄打开操作,以确定应用打开的虚拟机中的文件句柄,在一种实施方式中,本申请实施例提供的确定应用打开的虚拟机中的文件句柄的方法,具体可以包括:追踪所述应用的文件句柄打开操作;将追踪到的所述应用打开的文件句柄与所述应用对应的租户关联并保存。
通过追踪应用的文件句柄打开操作,当追踪到应用打开文件句柄时,可以将应用打开的文件句柄与该应用对应的用户租户关联保存(比如,可以在文件句柄表中保存应用打开的文件句柄),而当追踪到应用关闭某个文件句柄时,则可以将与用户租户关联保存的该文件句柄删除,则被保存的文件句柄均为应用打开的文件句柄。
则后续在对应用打开的虚拟机中的文件句柄进行回收时,可以关闭与所述应用对应的租户关联保存的文件句柄。
需要说明的是,当应用通过打开文件句柄读取文件数据时,在虚拟机中与该应用对应的用户租户中的线程将等待对文件数据读取而返回的读取结果,此时该线程将无法被关闭,而将应用打开的文件句柄关闭后,将唤醒等待的线程,进而可以通过上文提到的线程回收方法,回收被唤醒的线程,因而在对应用使用的资源进行回收时,往往可以先对应用打开的文件句柄进行回收,后续在对应用使用的线程以及共享变量对象进行回收。
本申请实施例还提供了一种资源回收装置,用以解决现有技术在对应用进行热部署升级时产生的资源泄露问题。该装置的具体结构示意图如图7所示,包括:租户创建单元21以及资源回收单元22。
其中,租户创建单元21,针对部署在容器中的应用,在运行所述容器的虚拟机中创建所述应用对应的租户,以使所述应用使用所述租户在所述虚拟机中的资源运行;
资源回收单元22,在对所述应用进行热部署升级时,根据所述应用对应的租户,对所述应用使用的所述资源进行回收。
在一种实施方式中,租户创建单元21,通过所述容器,在所述虚拟机中创建与所述应用对应的租户上下文,所述租户上下文用于表征所述应用对应的租户。
在一种实施方式中,所述虚拟机中还包含根租户,所述根租户用于向所述应用对应的租户提供运行所述应用所需的部分或全部资源。
在一种实施方式中,所述应用使用的资源,包括以下至少一种:所述应用使用的所述虚拟机中的线程;所述应用打开的所述虚拟机中的文件句柄;所述应用使用的所述虚拟机中的共享变量对象。
在一种实施方式中,所述应用使用的所述虚拟机中的线程,包括以下至少一种:由所述根租户的线程切换得到的线程;所述应用自身创建的线程。
在一种实施方式中,租户创建单元21,当所述虚拟机中的线程为由所述根租户的线程切换得到的线程时,通过所述容器,将所述虚拟机根租户的线程切换到所述应用对应的租户上下文中运行。
在一种实施方式中,资源回收单元22,根据所述应用对应的租户,对所述租户中运行的线程抛出异常对象;根据异常处理机制,对抛出异常对象的线程进行关闭。
在一种实施方式中,资源回收单元22,当所述应用使用的线程为所述应用自身创建的线程时,对所述应用对应的租户中应用自身创建的线程进行标记;针对携带有所述标记的线程抛出异常对象;修改携带有标记的线程栈上所有方法的异常处理机制,以使得根据所述异常处理机制无法查询到与所述抛出异常对象对应的异常类型;根据异常处理机制,对所述抛出异常对象的线程进行退栈。
在一种实施方式中,资源回收单元22,当所述应用使用的线程为由所述根租户的线程切换得到的线程时,针对所述应用对应的租户中由根租户的线程切换得到的线程抛出异常对象;修改由根租户的线程切换得到的线程的异常处理机制,以使得根据所述异常处理机制无法查询到与所述抛出异常对象对应的异常类型;对所述由根租户的线程切换得到的线程中、表示根租户线程入口的方法进行标记,以使得携带有所述标记的方法中存的异常对象能够被异常处理机制捕捉;根据异常处理机制,对携带有所述标记的方法中存的异常对象进行抓取,并将所述方法表示的线程切换回所述根租户的上下文中。
在一种实施方式中,资源回收单元22,当所述应用使用所述虚拟机中的共享变量对象时,对所述共享变量对象进行复制,获得所述共享变量对象的副本;将所述共享变量对象的副本保存到与所述应用对应租户的存储空间,以使得所述应用运行时使用保存在所述存储空间中的共享变量对象副本。
在一种实施方式中,资源回收单元22,删除保存在与所述应用对应的租户的存储空间中的共享变量对象副本;回收所述存储空间。
在一种实施方式中,资源回收单元,追踪所述应用的文件句柄打开操作;将追踪到的所述应用打开的文件句柄与所述应用对应的租户关联并保存。
在一种实施方式中,资源回收单元,关闭与所述应用对应的租户关联保存的文件句柄。
采用本申请实施例提供的资源回收方法,由于可以针对部署在容器中的应用,在运行所述容器的虚拟机中创建所述应用对应的租户,以使所述应用使用所述租户在所述虚拟机中的资源运行,因而可以根据应用在虚拟机中对应的租户中的资源,确定应用运行时使用的虚拟机中的资源,则在对应用进行热部署升级时,可以根据该应用对应的租后,对所述应用使用的资源进行回收,从而避免了在对应用进行热部署升级时,产生的资源泄露问题。
本领域内的技术人员应明白,本发明的实施例可提供为方法、系统、或计算机程序产品。因此,本发明可采用完全硬件实施例、完全软件实施例、或结合软件和硬件方面的实施例的形式。而且,本发明可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、CD-ROM、光学存储器等)上实施的计算机程序产品的形式。
本发明是参照根据本发明实施例的方法、设备(系统)、和计算机程序产品的流程图和/或方框图来描述的。应理解可由计算机程序指令实现流程图和/或方框图中的每一流程和/或方框、以及流程图和/或方框图中的流程和/或方框的结合。可提供这些计算机程序指令到通用计算机、专用计算机、嵌入式处理机或其他可编程数据处理设备的处理器以产生一个机器,使得通过计算机或其他可编程数据处理设备的处理器执行的指令产生用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的装置。
这些计算机程序指令也可存储在能引导计算机或其他可编程数据处理设备以特定方式工作的计算机可读存储器中,使得存储在该计算机可读存储器中的指令产生包括指令装置的制造品,该指令装置实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能。
这些计算机程序指令也可装载到计算机或其他可编程数据处理设备上,使得在计算机或其他可编程设备上执行一系列操作步骤以产生计算机实现的处理,从而在计算机或其他可编程设备上执行的指令提供用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的步骤。
在一个典型的配置中,计算设备包括一个或多个处理器(CPU)、输入/输出接口、网络接口和内存。
内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(RAM)和/或非易失性内存等形式,如只读存储器(ROM)或闪存(flash RAM)。内存是计算机可读介质的示例。
计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(PRAM)、静态随机存取存储器(SRAM)、动态随机存取存储器(DRAM)、其他类型的随机存取存储器(RAM)、只读存储器(ROM)、电可擦除可编程只读存储器(EEPROM)、快闪记忆体或其他内存技术、只读光盘只读存储器(CD-ROM)、数字多功能光盘(DVD)或其他光学存储、磁盒式磁带,磁带磁磁盘存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括暂存电脑可读媒体(transitory media),如调制的数据信号和载波。
还需要说明的是,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、商品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、商品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个……”限定的要素,并不排除在包括所述要素的过程、方法、商品或者设备中还存在另外的相同要素。
本领域技术人员应明白,本申请的实施例可提供为方法、系统或计算机程序产品。因此,本申请可采用完全硬件实施例、完全软件实施例或结合软件和硬件方面的实施例的形式。而且,本申请可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、CD-ROM、光学存储器等)上实施的计算机程序产品的形式。
以上所述仅为本申请的实施例而已,并不用于限制本申请。对于本领域技术人员来说,本申请可以有各种更改和变化。凡在本申请的精神和原理之内所作的任何修改、等同替换、改进等,均应包含在本申请的权利要求范围之内。