终端中应用启动时的内存分配方法及其***
技术领域
本发明涉及终端应用技术,特别涉及终端中应用启动时的内存分配方法及其***。
背景技术
在android或者类android***中,应用启动时的用户体验主要体现在应用启动时间的长短和应用启动动画的平滑程度上。这两个方面都跟应用启动时的内存的大小和分配方法有关。在内存有限的情况下,对内存需求较高的应用比如游戏等可能会面临启动时间长、启动动画卡顿等用户体验问题。
在android***里,每个应用在启动时,***会为其分配一块大小为S0的Java堆内存空间,用以存放程序在启动和运行时动态产生的Java类对象等相关数据。Java堆是由垃圾回收器管理的,不再需要的对象数据会被垃圾回收器清除,清理出来的堆空间可以用来存放其它对象数据。
现有android***无法预知每个应用所需Java堆空间的大小,为了不浪费内存,S0的取值会相对较小。如果应用在启动过程中产生大量对象数据,经过垃圾回收后仍不能满足分配需求,***会动态增加该应用的堆空间容量。这样一来,在应用启动阶段,堆空间的大小会随着启动的推进而不断增加,总体呈现为递增序列{S0,S1,S2,S3…}。
本发明的发明人发现,对所有应用的每次启动,现有android***都是从一个统一的较小值S0开始,根据应用需求逐步增加Java堆空间大小。这样做的好处是不浪费内存,但是存在一个缺点,会降低应用启动时的用户体验。在应用启动阶段,这种机制会触发垃圾回收,垃圾回收是有时间代价的,它会造成启动时间的增加和启动动画的卡顿。
发明内容
本发明的目的在于提供一种终端中应用启动时的内存分配方法及其***,在不增加内存总量的前提下,有效减少了应用启动期间的垃圾回收次数。
为解决上述技术问题,本发明的实施方式公开了一种终端中应用启动时的内存分配方法,该方法包括以下步骤:
记录应用每次启动后实际分配的Java堆大小;
根据已记录的应用的实际分配的Java堆大小计算该应用下一次启动的Java堆预测值;
根据Java堆预测值,在应用下一次启动时为该应用初始分配Java堆。
本发明的实施方式还公开了一种终端中应用启动时的内存分配***,该***包括:
记录模块,用于记录应用每次启动后实际分配的Java堆大小;
计算模块,用于根据记录模块已记录的应用的实际分配的Java堆大小计算该应用下一次启动的Java堆预测值;以及
分配模块,用于根据计算模块计算的Java堆预测值,在应用下一次启动时为该应用初始分配Java堆。
本发明实施方式与现有技术相比,主要区别及其效果在于:
在本发明中,根据已记录的应用每次启动后实际分配的Java堆大小计算该应用下一次启动的Java堆预测值,并根据该Java堆预测值在该应用下一次启动时为该应用初始分配Java堆,在不增加内存总量的前提下,有效减少了应用启动期间的垃圾回收次数,从而减少应用启动时间,提高启动动画平滑度。
进一步地,选取c为0.4~0.6之间的值,既可以保证每次启动的Java堆预测值不断逼近实际分配的Java堆大小,又可以避免每次启动时初始分配的Java堆大小的波动,以造成不必要的内存浪费。
进一步地,考虑更多次启动后实际分配的Java堆大小,使得下一次启动的Java堆预测值更准确。
附图说明
图1是本发明第一实施方式中一种终端中应用启动时的内存分配方法的流程示意图;
图2是android***上典型的应用启动过程的示意图。
图3和图4分别是c取值为0.8和0.2时预测结果与M值的曲线图。
图5是本发明第二实施方式中一种终端中应用启动时的内存分配***的结构示意图。
具体实施方式
在以下的叙述中,为了使读者更好地理解本申请而提出了许多技术细节。但是,本领域的普通技术人员可以理解,即使没有这些技术细节和基于以下各实施方式的种种变化和修改,也可以实现本申请各权利要求所要求保护的技术方案。
为使本发明的目的、技术方案和优点更加清楚,下面将结合附图对本发明的实施方式作进一步地详细描述。
本发明第一实施方式涉及一种终端中应用启动时的内存分配方法。图1是该终端中应用启动时的内存分配方法的流程示意图。可以理解,上述终端可以为智能手机、平板电脑、电视机、数码相机、游戏机等等。
如图1所示,该方法包括以下步骤:
在步骤101中,记录应用每次启动后实际分配的Java堆大小。
此后进入步骤102,根据已记录的应用的实际分配的Java堆大小计算该应用下一次启动的Java堆预测值。
此后进入步骤103,根据Java堆预测值,在应用下一次启动时为该应用初始分配Java堆。
此后结束本流程。
可选地,上述方法应用于安卓***或类安卓***。此外,可以理解,在本发明的其他实施方式中,上述方法也可以应用于使用Java语言的其他操作***中。
在本实施方式的方法中,根据已记录的应用每次启动后实际分配的Java堆大小计算该应用下一次启动的Java堆预测值,并根据该Java堆预测值在该应用下一次启动时为该应用初始分配Java堆,在不增加内存总量的前提下,有效减少了应用启动期间的垃圾回收次数,从而减少应用启动时间,提高启动动画平滑度。
其中,在步骤102中可以以各种方式对该应用下一次启动的Java堆预测值进行计算,具体地说:
可以在步骤102中,根据Sn-1=c*Sn-2+c'*Mn-2计算该应用第n次启动的Java堆预测值,n为大于1的整数。
其中,Sn-1为该应用第n次启动的Java堆预测值,Sn-2为该应用第n-1次启动的Java堆预测值,Mn-2为该应用第n-1次启动后实际分配的Java堆大小,0<c<1,0<c'<1,且c+c'=1。
优选地,c可以为0.4~0.6之间的值。选取c为0.4~0.6之间的值,既可以保证每次启动的Java堆预测值不断逼近实际分配的Java堆大小,又可以避免每次启动时初始分配的Java堆大小的波动,以造成不必要的内存浪费。
需注意的是,当直接取c=0时,Sn-1=Mn-2,…,S2=M1,S1=M0,相当于直接按照上一次启动完成时Java堆的大小来为下一次启动分配堆。这样做,虽然可能会产生波动,但优化效果通常比较显著。
也可以在步骤102中把以往历次启动的Java堆大小都考虑进来,即根据Sn-1=c0*Mn-2+c1*Mn-3+…+cn-2*M0计算该应用第n次启动的Java堆预测值,n为大于1的整数。
其中,Sn-1为该应用第n次启动的Java堆预测值,M0、M1…,Mn-2分别为该应用第1次、第2次…,第n-1次启动后实际分配的Java堆大小,0<c0,c1…,cn-2<1,且c0+c1+…+cn-2=1。
可以理解,在本发明的各个实施方式中,可以对M0、M1…,Mn-2进行算术平均以得到Sn-1,即c0=c1=…=cn-2=1/(n-1),也可以对M0、M1…,Mn-2进行加权平均,即可以为c0,c1…,cn-2选择不同的取值,在一优选实例中,选择c0>c1>…>cn-2,以使得最近几次启动后实际分配的Java堆大小的权重更大,或使用其他函数来进行计算。
此外,可以理解,在本发明的其他实施方式中,也可以根据需要仅考虑前两次、前三次或前m次(m为整数)启动后实际分配的Java堆大小以对下一次启动的Java堆预测值进行计算。
考虑更多次启动后实际分配的Java堆大小,可以使下一次启动的Java堆预测值更准确。
在实际操作时,可以根据需要选择上述计算方式中的一种或其组合。例如在启动该应用的前几次采用前一种方式,之后采用后一种方式,以达到更佳的效果。
此外,可以理解,在本发明的其他实施方式中,也可以不根据历史数据来计算上述应用下一次启动的Java堆预测值,在安装应用的同时即通过分析应用本身的内存使用情况来计算该应用启动的Java堆预测值。
由上可以看到,为了减少垃圾回收次数,提升应用启动时的用户体验,本发明提出了一种新的内存分配方法:预测每一个应用在下次启动时所需最大Java堆大小M,当用户下次启动该应用时,***将直接分配大小为M的堆给该应用。这样,应用启动期间发生垃圾回收的次数就会减少,从而减少了应用启动时间和启动动画的卡顿。
我们在此对该预测方法作几点说明。首先,上述预测方法针对的是每一个应用。因为每个应用在启动时所需最大Java堆大小都不相同,本发明针对每个应用预测出的最大堆大小也是不同的。其次,上述预测方法预测的是应用启动期间所需堆大小。最后,每个应用的启动时间长短不一,所以需要界定“启动期间”。如图2所示,以android***上典型的应用启动过程为例,本发明所使用的“启动期间”包括从“1用户点击应用启动图标”到“4应用第一帧显示”共四个步骤。
以下将进一步以安卓***和Sn-1=c*Sn-2+c'*Mn-2为例对上述方法进行详细描述。具体如下:
(1)应用第一次启动时采用与现有android***相同的堆分配方法,即先分配大小为S0的Java堆,其中S0是一个统一的较小值,应用在启动过程中会动态增加堆空间容量。当启动过程完成时,***会收到“Displayed”消息,表示应用第一帧已经显示。此时我们记下应用当前Java堆大小M0。
(2)应用第二次启动时,直接分配大小为S1的Java堆,S1=c*S0+c’*M0(其中0<c<1,0<c’<1,且c+c’=1),通常情况下c取0~1中间值0.5,也可以根据实际需要选择0~1之间的其他取值。当启动过程完成时,记下当前Java堆大小M1。
(3)依次类推,应用第n次启动时,直接分配大小为Sn-1的Java堆,Sn-1=c*Sn-2+c’*Mn-2(其中0<c<1,0<c’<1,且c+c’=1)。当启动过程完成时,记下当前Java堆大小Mn-1。
下面将对c的取值稍作说明,以了解c的取值对预测的影响。如果c=1,则Sn-1=Sn-2=…=S1=S0,上述预测方法将退化成现有android***所使用的堆分配方法;如果c=0,则Sn-1=Mn-2,…,S2=M1,S1=M0,上述预测方法相当于直接按照上一次启动完成时Java堆的大小来为下一次启动分配堆。因为应用每次启动完成时Java堆的大小可能并不相同,这跟S0的取值有关,也跟应用本身的实现有关(例如应用更新),如果直接取c=0,可能会造成Sn随着Mn-1波动。优选地,在本实施例中,c取0~1中间值0.5,这样既可以保证预测结果不断逼近真实值,也可以避免预测结果不必要的波动。
此外,也可以根据***的设计倾向对c取0~1之间其它值。如图3和图4所示,当c越接近1时(例如c=0.8),预测结果逼近M值越慢;当c越接近0时(例如c=0.2),预测结果逼近M值越快,但是波动更大,即如图4所示,在第3次和第4次启动时预测结果大于M值,在第5次和第6次启动时预测结果小于M值,则在预测结果大于M值时会造成一定的内存浪费。因此,我们可以根据***的设计倾向对c进行灵活取值。如果追求更快见效,可以使用接近0的取值;如果追求稳定性,可以使用接近1的取值。
因此,本发明提出了一种新的内存分配策略,可以在不增加内存总量的前提下,更加合理的分配内存,从而减少应用启动时间,提高启动动画平滑度。
可以理解,以上仅为一优选例,在本发明的其他实施例中,也可以根据需要使用其他计算方式或其组合,并应用于使用Java语言的其他操作***中。
本发明的各方法实施方式均可以以软件、硬件、固件等方式实现。不管本发明是以软件、硬件、还是固件方式实现,指令代码都可以存储在任何类型的计算机可访问的存储器中(例如永久的或者可修改的,易失性的或者非易失性的,固态的或者非固态的,固定的或者可更换的介质等等)。同样,存储器可以例如是可编程阵列逻辑(Programmable ArrayLogic,简称“PAL”)、随机存取存储器(Random Access Memory,简称“RAM”)、可编程只读存储器(Programmable Read Only Memory,简称“PROM”)、只读存储器(Read-Only Memory,简称“ROM”)、电可擦除可编程只读存储器(Electrically Erasable Programmable ROM,简称“EEPROM”)、磁盘、光盘、数字通用光盘(Digital Versatile Disc,简称“DVD”)等等。
本发明第二实施方式涉及一种终端中应用启动时的内存分配***。图5是该终端中应用启动时的内存分配***的结构示意图。如图5所示,该***包括:
记录模块,用于记录应用每次启动后实际分配的Java堆大小。
计算模块,用于根据记录模块已记录的应用的实际分配的Java堆大小计算该应用下一次启动的Java堆预测值。以及
分配模块,用于根据计算模块计算的Java堆预测值,在应用下一次启动时为该应用初始分配Java堆。
可选地,上述***应用于安卓***或类安卓***。此外,可以理解,在本发明的其他实施方式中,上述***也可以应用于使用Java语言的其他操作***中。
在本实施方式的***中,计算模块根据已记录的应用每次启动后实际分配的Java堆大小计算该应用下一次启动的Java堆预测值,分配模块根据该Java堆预测值在该应用下一次启动时为该应用初始分配Java堆,在不增加内存总量的前提下,有效减少了应用启动期间的垃圾回收次数,从而减少应用启动时间,提高启动动画平滑度。
其中,上述计算模块可以以各种方式对该应用下一次启动的Java堆预测值进行计算,具体地说:
上述计算模块可以用于根据Sn-1=c*Sn-2+c'*Mn-2来计算应用第n次启动的Java堆预测值,n为大于1的整数。
其中,Sn-1为应用第n次启动的Java堆预测值,Sn-2为应用第n-1次启动的Java堆预测值,Mn-2为应用第n-1次启动后实际分配的Java堆大小,0<c<1,0<c'<1,且c+c'=1。
优选地,c为0.4~0.6。选取c为0.4~0.6,既可以保证每次启动的Java堆预测值不断逼近实际分配的Java堆大小,又可以避免每次启动时初始分配的Java堆大小的波动,以造成不必要的内存浪费。
需注意的是,当直接取c=0时,Sn-1=Mn-2,…,S2=M1,S1=M0,相当于直接按照上一次启动完成时Java堆的大小来为下一次启动分配堆。这样做,虽然可能会产生波动,但优化效果通常比较显著。
上述计算模块也可以用于根据Sn-1=c0*Mn-2+c1*Mn-3+…+cn-2*M0来计算应用第n次启动的Java堆预测值。
其中,Sn-1为应用第n次启动的Java堆预测值,M0、M1…,Mn-2分别为应用第1次、第2次…,第n-1次启动后实际分配的Java堆大小,0<c0,c1…,cn-2<1,且c0+c1+…+cn-2=1。
可以理解,在本发明的各个实施方式中,可以对M0、M1…,Mn-2进行算术平均以得到Sn-1,即c0=c1=…=cn-2=1/(n-1),也可以对M0、M1…,Mn-2进行加权平均,即可以为c0,c1…,cn-2选择不同的取值,在一优选实例中,选择c0>c1>…>cn-2,以使得最近几次启动后实际分配的Java堆大小的权重更大,或使用其他函数来进行计算。
此外,可以理解,在本发明的其他实施方式中,也可以根据需要仅考虑前两次、前三次或前m次(m为整数)启动后实际分配的Java堆大小对下一次启动的Java堆预测值进行计算。
考虑更多次启动后实际分配的Java堆大小,可以使下一次启动的Java堆预测值更准确。
在实际操作时,可以根据需要选择上述计算方式中的一种或其组合。例如在启动该应用的前几次采用前一种方式,之后采用后一种方式,以达到更佳的效果。
此外,可以理解,在本发明的其他实施方式中,也可以不根据历史数据来计算上述应用下一次启动的Java堆预测值,在安装应用的同时即通过分析应用本身的内存使用情况来计算该应用启动的Java堆预测值。
第一实施方式是与本实施方式相对应的方法实施方式,本实施方式可与第一实施方式互相配合实施。第一实施方式中提到的相关技术细节在本实施方式中依然有效,为了减少重复,这里不再赘述。相应地,本实施方式中提到的相关技术细节也可应用在第一实施方式中。
需要说明的是,本发明各设备实施方式中提到的各模块都是逻辑模块,在物理上,一个逻辑模块可以是一个物理模块,也可以是一个物理模块的一部分,还可以以多个物理模块的组合实现,这些逻辑模块本身的物理实现方式并不是最重要的,这些逻辑模块所实现的功能的组合才是解决本发明所提出的技术问题的关键。此外,为了突出本发明的创新部分,本发明上述各设备实施方式并没有将与解决本发明所提出的技术问题关系不太密切的模块引入,这并不表明上述设备实施方式并不存在其它的模块。
需要说明的是,在本专利的权利要求和说明书中,诸如第一和第二等之类的关系术语仅仅用来将一个实体或者操作与另一个实体或操作区分开来,而不一定要求或者暗示这些实体或操作之间存在任何这种实际的关系或者顺序。而且,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、物品或者设备不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、物品或者设备所固有的要素。在没有更多限制的情况下,由语句“包括一个”限定的要素,并不排除在包括所述要素的过程、方法、物品或者设备中还存在另外的相同要素。
虽然通过参照本发明的某些优选实施方式,已经对本发明进行了图示和描述,但本领域的普通技术人员应该明白,可以在形式上和细节上对其作各种改变,而不偏离本发明的精神和范围。