发明内容
本申请的目的在于,提供一种数据存储方法及装置,以解决内存利用率低的问题。
为了解决上述问题,本申请公开了一种数据存储方法,包括:
接收数据存储请求,并获得请求的数据大小M;
将请求的数据大小M与内存中当前指针指向的空闲内存块的大小N进行比较,若M小于等于N,则将该空闲内存块分配给请求数据;
若M大于N,并且内存空闲,则从内存申请大小为P的空闲内存块并分配给请求数据,其中P大于N;
若请求的数据大小M大于所述空闲内存块的大小P,则再将内存中的一个或多个可用内存块分配给M-P大小的请求数据,并将存有请求数据的所有内存块通过指针相连。
优选地,所述可用内存块为零散内存块。
优选地,所述方法还包括:将内存块的大小分级,每个级别对应一个链表,其中P对应一个级别;按照大小级别分配内存块,并将已分配的内存块分别插入对应级别的链表中。
优选地,所述从内存申请大小为P的空闲内存块并分配给请求数据,包括:若请求的数据大小M小于P,并且M符合某些小于P的级别,则将请求数据按照所选级别分拆,并从大小为P的空闲内存块中按照所选级别分割出一个或多个内存块分配给分拆后的请求数据,并将所述已分配的内存块分别插入对应级别的链表中。
优选地,所述将内存中的一个或多个可用内存块分配给M-P大小的请求数据,包括:如果内存空闲,则从内存申请大小为P的空闲内存块并分配给M-P大小的请求数据。
优选地,所述将内存中的一个或多个可用内存块分配给M-P大小的请求数据,包括:如果内存没有大小为P的空闲内存块,并且已分配的内存块中有剩余,则从已分配的一个或多个内存块中分割出剩余未用部分,作为一个或多个可用内存块分配给M-P大小的请求数据。
优选地,所述从已分配的一个或多个内存块中分割出剩余未用部分,作为一个或多个可用内存块分配给M-P大小的请求数据,包括:若从一个已分配的内存块中分割出的剩余未用部分大于等于M-P,则将该剩余未用部分作为一个可用内存块分配给M-P大小的请求数据;否则,将M-P大小的请求数据按照所选级别分拆,并从多个已分配的内存块中分割出剩余未用部分,每个剩余未用部分作为一个级别的可用内存块,分配给M-P大小的分拆后的请求数据。
优选地,所述将内存中的一个或多个可用内存块分配给M-P大小的请求数据,还包括:如果从已分配的内存块中无法分割出有效块,则根据内存块的分组排列选择最空的分组,将该分组中每个内存块的剩余未用部分进行合并,并将合并后的内存块分配给M-P大小的请求数据。
优选地,所述方法还包括:将内存中最近最少使用的内存块释放。
优选地,所述方法还包括:对请求数据进行两层配置,第一层配置采用内存存储,第二层配置采用文件存储。
本申请还提供了一种数据存储装置,包括:
请求接收模块,用于接收数据存储请求,并获得请求的数据大小M;
第一分配模块,用于将请求的数据大小M与内存中当前指针指向的空闲内存块的大小N进行比较,若M小于等于N,则将该空闲内存块分配给请求数据;
第二分配模块,用于当M大于N,并且内存空闲时,从内存申请大小为P的空闲内存块并分配给请求数据,其中P大于N;
第三分配模块,用于当请求的数据大小M大于所述空闲内存块的大小P时,再将内存中的一个或多个可用内存块分配给M-P大小的请求数据;
内存块连接模块,用于将存有请求数据的所有内存块通过指针相连。
优选地,所述可用内存块为零散内存块。
优选地,所述装置还包括:内存分级模块,用于将内存块的大小分级,每个级别对应一个链表,其中P对应一个级别;内存分配时按照大小级别分配内存块,并将已分配的内存块分别插入对应级别的链表中。
优选地,若请求的数据大小M小于P,并且M符合某些小于P的级别,则第二分配模块将请求数据按照所选级别分拆,并从大小为P的空闲内存块中按照所选级别分割出一个或多个内存块分配给分拆后的请求数据,并将所述已分配的内存块分别插入对应级别的链表中。
优选地,如果内存空闲,则所述第三分配模块从内存申请大小为P的空闲内存块并分配给M-P大小的请求数据。
优选地,如果内存没有大小为P的空闲内存块,并且已分配的内存块中有剩余,则从所述第三分配模块已分配的一个或多个内存块中分割出剩余未用部分,作为一个或多个可用内存块分配给M-P大小的请求数据。
优选地,若从一个已分配的内存块中分割出的剩余未用部分大于等于M-P,则所述第三分配模块将该剩余未用部分作为一个可用内存块分配给M-P大小的请求数据;否则,所述第三分配模块将M-P大小的请求数据按照所选级别分拆,并从多个已分配的内存块中分割出剩余未用部分,每个剩余未用部分作为一个级别的可用内存块,分配给M-P大小的分拆后的请求数据。
优选地,如果从已分配的内存块中无法分割出有效块,则所述第三分配模块根据内存块的分组排列选择最空的分组,将该分组中每个内存块的剩余未用部分进行合并,并将合并后的内存块分配给M-P大小的请求数据。
与现有技术相比,本申请包括以下优点:
首先,本申请在内存分页存储管理机制的基础上,对于请求的数据,如果能够存入分页分配的内存块中,则选择空闲内存块存储;如果数据大小大于分页分配的内存块,则将其中一部分数据存入该内存块,将另一部分剩余数据存入内存中的一个或多个可用内存块中,并将存有请求数据的所有内存块通过指针相连。其中,所述可用内存块为大小不一的零散内存块,可用内存块可能是新申请的内存块,也可能是已分配的内存块中剩余未用的内存块,还可能是内存碎片合并后的内存块,其大小依请求数据的大小而确定,并不一定与分页分配的内存块大小相同。因此,本申请可以尽量避免内存浪费,最大限度地提高内存利用率。
其次,本申请采用内存分级的方式,并且每个级别对应一个链表,内存分配时按照大小级别分配内存块,并将已分配的内存块分别插入对应级别的链表中。通过这种方式,可以高效率地插入、查找和删除一个数据。
再次,本申请还可以采用内存存储和文件存储相结合的数据存储方式,其中第一层采用内存存储方式提高内存效率,第二层采用文件存储提高命中率。
当然,实施本申请的任一产品不一定需要同时达到以上所述的所有优点。
具体实施方式
为使本申请的上述目的、特征和优点能够更加明显易懂,下面结合附图和具体实施方式对本申请作进一步详细的说明。
本申请提供了一种数据存储方法及装置,可以提高内存利用率。下面通过实施例对本申请所述方法的实现流程进行详细说明。
参照图1,是本申请实施例所述一种数据存储方法的流程图。
步骤101,接收数据存储请求,并获得请求的数据大小M;
步骤102,将请求的数据大小M与内存中当前指针指向的空闲内存块的大小N进行比较,若M小于等于N,则将该空闲内存块分配给请求数据;
其中当前指针指向的空闲内存块是指已向内存申请空间但还没有分配给任何数据使用的空闲内存;
步骤103,若M大于N,并且内存空闲,则从内存申请大小为P的空闲内存块并分配给请求数据,其中P大于N;
步骤104,若请求的数据大小M大于所述空闲内存块的大小P,则再将内存中的一个或多个可用内存块分配给M-P大小的请求数据,并将存有请求数据的所有内存块通过指针相连。
例如,按照一般的内存分页管理机制,每次可申请固定大小如4k(即P值)的内存空间,如果这4k的空间已分配出去2k,则还剩下2k(即N值)的空间,那么当前指针则指向这剩余2k空间的起始地址。此时,如果正好有一个2k(即M值)大小的数据请求存储到内存中,则按照步骤102的处理,可以将当前指针指向的剩余2k空间分配给该数据。如果请求的数据大小小于2k,也可以将这剩余的2k空间分配给该数据。
但是,如果请求的数据大小大于2k,则无法全部存入这剩余的2k空间内,此时按照步骤103如果内存空闲需要重新申请内存空间,按照内存分页管理机制,可申请4k(即P值)的内存空间。
如果请求的数据大小大于2k小于4k,则可以全部存入新分配的4k内存块中。如果请求的数据大小大于4k,例如为6k,则按照步骤104将其中4k的数据存入4k大小的内存块中,将剩余2k(即M-P的值)的数据存入内存的其他可用内存块中。假设剩余2k的数据存入了一个2k的可用内存块中,那么最终这个6k大小的数据就被拆分存入了一个4k大小的内存块和一个2k大小的内存块中。这两个内存块通过指针连接,其中第一个4k内存块的末尾通过指针指向第二个2k内存块的开头,第二个2k内存块的末尾通过结束符标识数据结束,这样读取数据时根据每个内存块的末尾标识就能够将全部的6k数据读出。
本申请实施例中,所述可用内存块为大小不一的零散内存块,可用内存块可能是新申请的内存块,也可能是已分配的内存块中剩余未用的内存块,还可能是内存碎片合并后的内存块,后面将通过例子详细说明,在此略。
基于上述内容,在另一优选实施例中,进行内存分配管理时还采用了内存分级方式,即将内存块按照大小不等分为多个级别,并且每个级别对应一个链表,内存分配时按照大小级别分配内存块,并将已分配的内存块分别插入对应级别的链表中。这样,同一个级别下相同大小的多个已分配的内存块通过指针相互连接构成一个链表。例如,将一个内存空间从4k到64b分为以下几个等级:4k,2k,1k,...,128b,96b,64b,每次为请求数据分配内存时,按照选定的级别分配相应大小的内存块。
结合上述内存分级,上述步骤103中从内存申请大小为P的空闲内存块并分配给请求数据,具体可以包括以下处理:
若请求的数据大小M小于P,并且M符合某些小于P的级别,则将请求数据按照所选级别分拆,并从大小为P的空闲内存块中按照所选级别分割出一个或多个内存块分配给分拆后的请求数据,并将所述已分配的内存块分别插入对应级别的链表中。
例如,请求的数据大小为2k+128b,而每次申请的空闲内存块的大小为4k,此时小于4k的分级有2k,1k,...,128b,96b,64b,则可以将请求数据分拆为2k和128b两部分,同时从4k的空闲内存块中分割出2k的块和128b的块,分配给2k和128b的请求数据。最后,还要将这个2k的块插入2k级别的链表中,并将128b的块插入128b级别的链表中。此外,2k的块的末尾指针还指向128b的块,128b的块的末尾填入结束符,表示该请求数据结束。
实际应用中,对于某些特定的应用,可以将新分配的内存块插入对应链表的末尾,而对于另外的应用,还可以将新分配的内存块插入对应链表的最前端。例如,对于热点数据,如微博上的一条条信息等,用户更多关注的是微博用户发布的最新消息,而不是那些发布了很多天的信息,所以可以将存有最新数据的内存块自动排到对应链表的最前端,方便读取并显示,提高了业务的处理效率。
基于上述内容,在另一优选实施例中,步骤104中若请求的数据大小M大于所述空闲内存块的大小P,则再将内存中的一个或多个可用内存块分配给M-P大小的请求数据,具体可以包括以下处理:
首先,如前所述,请求数据中的一部分数据先存满到大小为P的空闲内存块中,请求数据的剩余部分M-P则存储到可用内存块中,可用内存块的分配过程如下:
1)如果内存空闲,即内存有大小为P的空闲空间,则从内存申请大小为P的空闲内存块并分配给M-P大小的请求数据。
例如,若请求数据的大小是6k+96b,则其中4k的数据存入第一个分配的内存块中,然后再申请4k的内存块,并分割出2k的块和96b的块来分别存储剩余2k的数据和96b的数据。最后,参照图2所示,将4k、2k、96b的内存块(图中标粗的方框)分别插入对应级别的链表中,并且4k、2k、96b的内存块通过图中的粗指针相连。其中,每个级别的链表都有一个头指针。
如果1)无法满足,则采用2)的方法。
2)如果内存没有大小为P的空闲内存块,并且已分配的内存块中有剩余,则从已分配的一个或多个内存块中分割出剩余未用部分,作为一个或多个可用内存块分配给M-P大小的请求数据。
具体的,若从一个已分配的内存块中分割出的剩余未用部分大于等于M-P,则将该剩余未用部分作为一个可用内存块分配给M-P大小的请求数据;
否则,将M-P大小的请求数据按照所选级别分拆,并从多个已分配的内存块中分割出剩余未用部分,每个剩余未用部分作为一个级别的可用内存块,分配给M-P大小的分拆后的请求数据。
例如,如果内存已分配不出4k大小的空间,即内存已用完,但是如果已分配出去的内存块中还有剩余空间,则还没有达到内存使用上限。此时,可以利用这些已分配块的剩余空间来存储请求数据。对于2k的剩余请求数据,如果某个已分配块还剩下2k的空闲空间,则可以将这2k的空间分割出来存储2k的剩余请求数据,然后将这个2k的块插入2k级别的链表中,同时还要将原来的已分配块调整到大小变更后的级别中,由于原来的已分配块从4k变为2k,所以重新插入2k的链表中。
但是,如果已分配块没有完整的2k空间,而只有两个已分配块分别有1k的剩余空间,则需要从这两个已分配块中分别分割出1k的剩余块,并对2k的剩余请求数据分拆为1k+1k两部分,分别存入分割出的内存块中。然后,把这两个1k的内存块插入1k级别的链表中。
再例如,如果剩余的请求数据为2k+96b,可以从两个已分配块中找到2k的剩余空间和96b的剩余空间,将剩余的请求数据分拆后存入。这种方法比存入一个3k剩余块更能提高内存利用率。因此,如何使用已分配块的剩余空间,可根据实际数据的大小灵活分配。
如果2)也无法满足,则采用3)的方法。
3)如果从已分配的内存块中无法分割出有效块,则根据内存块的分组排列选择最空的分组,将该分组中每个内存块的剩余未用部分进行合并,并将合并后的内存块分配给M-P大小的请求数据。
所述有效块是指上述2)中可以从已分配块中分割出来的剩余块。
内存管理机制还可以对已分配的内存块进行分组管理,如将几个相邻块作为一组,每组的块的个数是一样的。如果2)不满足,则按照分组中剩余空间的大小进行分组排序,并选出剩余空间最多的分组,然后将该分组中的剩余空间合并后分配使用。
例如,剩余的请求数据为2k,已分配块的剩余部分分别是0.5k、1k、0.25k和0.25k,此时如果按照2)的方式分拆这2k的数据,就需要分拆为4部分,比较零散,所以采用3)的合并方式,将这四个已分配块的剩余部分合并成一个2k大小的内存块。
如果3)仍然无法满足,则采用4)的方法。
4)如果无可整理的分组,则将内存中最近最少使用的内存块释放。
本申请实施例中,内存存储还增加了自动淘汰机制,按照最近最少使用的方式释放部分内存块,以腾出更多的空闲内存。当然,也可以采用其他淘汰机制。
综上所述,本申请实施例所述方法在内存分页管理机制的基础上,对于请求的数据,如果能够存入分页分配的内存块中,则选择空闲内存块存储;如果数据大小大于分页分配的内存块,则将其中一部分数据存入该内存块,将另一部分剩余数据存入内存中的一个或多个可用内存块中,并将存有请求数据的所有内存块通过指针相连。其中,所述可用内存块为大小不一的零散内存块,可用内存块可能是新申请的内存块,也可能是已分配的内存块中剩余未用的内存块,还可能是内存碎片合并后的内存块,其大小依请求数据的大小而确定,并不一定与分页分配的内存块大小相同。因此,本申请可以尽量避免内存浪费,最大限度地提高内存利用率。
而且,还可以对请求数据进行两层配置,第一层配置采用内存存储以提高内存效率,第二层配置采用文件存储以提高命中率。
并且,由于采用链表结构,因此尤其适用于键值key-value数据的存储。可采用开链式Hash表来存放数据映射,数据的key和value组合存放。Hash的好处是效率高,并且适合分段迁移的需求。
实际应用中,具备高可靠性及可扩展性的海量数据存储对互联网公司来说是一个巨大的挑战,传统的数据库往往很难满足该需求,并且很多时候对于特定的系统绝大部分的检索都是基于主键的查询,在这种情况下使用关系型数据库将使得效率低下,并且扩展也将成为未来很大的难题。在这样的情况下,使用Key-value存储将会是一个很好的选择。Key-value存储被广泛应用于缓存、搜索引擎等等领域。
需要说明的是,对于前述的方法实施例,为了简单描述,故将其都表述为一系列的动作组合,但是本领域技术人员应该知悉,本申请并不受所描述的动作顺序的限制,因为依据本申请,某些步骤可以采用其他顺序或者同时进行。其次,本领域技术人员也应该知悉,说明书中所描述的实施例均属于优选实施例,所涉及的动作并不一定是本申请所必需的。
基于上述方法实施例的说明,本申请还提供了相应的数据存储装置实施例,来实现上述方法实施例所述的内容。
参照图3,是本申请实施例所述一种数据存储装置的结构图。
所述数据存储装置可以包括以下模块:
请求接收模块10,用于接收数据存储请求,并获得请求的数据大小M;
第一分配模块20,用于将请求的数据大小M与内存中当前指针指向的空闲内存块的大小N进行比较,若M小于等于N,则将该空闲内存块分配给请求数据;
第二分配模块30,用于当M大于N,并且内存空闲时,从内存申请大小为P的空闲内存块并分配给请求数据,其中P大于N;
第三分配模块40,用于当请求的数据大小M大于所述空闲内存块的大小P时,再将内存中的一个或多个可用内存块分配给M-P大小的请求数据;
内存块连接模块50,用于将存有请求数据的所有内存块通过指针相连。
其中,所述可用内存块为零散内存块。
优选的,在另一实施例中,所述数据存储装置还可以包括:
内存分级模块,用于将内存块的大小分级,每个级别对应一个链表,其中P对应一个级别;内存分配时按照大小级别分配内存块,并将已分配的内存块分别插入对应级别的链表中。
优选的,若请求的数据大小M小于P,并且M符合某些小于P的级别,则第二分配模块30将请求数据按照所选级别分拆,并从大小为P的空闲内存块中按照所选级别分割出一个或多个内存块分配给分拆后的请求数据,并将所述已分配的内存块分别插入对应级别的链表中。
进一步的,如果内存空闲,则所述第三分配模块40从内存申请大小为P的空闲内存块并分配给M-P大小的请求数据。
进一步的,如果内存没有大小为P的空闲内存块,并且已分配的内存块中有剩余,则从所述第三分配模块40已分配的一个或多个内存块中分割出剩余未用部分,作为一个或多个可用内存块分配给M-P大小的请求数据。
进一步的,若从一个已分配的内存块中分割出的剩余未用部分大于等于M-P,则所述第三分配模块40将该剩余未用部分作为一个可用内存块分配给M-P大小的请求数据;否则,所述第三分配模块将M-P大小的请求数据按照所选级别分拆,并从多个已分配的内存块中分割出剩余未用部分,每个剩余未用部分作为一个级别的可用内存块,分配给M-P大小的分拆后的请求数据。
进一步的,如果从已分配的内存块中无法分割出有效块,则所述第三分配模块根据内存块的分组排列选择最空的分组,将该分组中每个内存块的剩余未用部分进行合并,并将合并后的内存块分配给M-P大小的请求数据。
优选的,在另一实施例中,所述数据存储装置还可以包括:
内存释放模块,用于将内存中最近最少使用的内存块释放。
优选的,在另一实施例中,所述数据存储装置还可以包括:
配置模块,用于对请求数据进行两层配置,第一层配置采用内存存储,第二层配置采用文件存储。
对于上述数据存储装置实施例而言,由于其与方法实施例基本相似,所以描述的比较简单,相关之处参见方法实施例的部分说明即可。
本说明书中的各个实施例均采用递进的方式描述,每个实施例重点说明的都是与其他实施例的不同之处,各个实施例之间相同相似的部分互相参见即可。
还需要说明的是,在本文中,诸如第一和第二等之类的关系术语仅仅用来将一个实体或者操作与另一个实体或操作区分开来,而不一定要求或者暗示这些实体或操作之间存在任何这种实际的关系或者顺序。
以上对本申请所提供的一种数据存储方法及装置,进行了详细介绍,本文中应用了具体个例对本申请的原理及实施方式进行了阐述,以上实施例的说明只是用于帮助理解本申请的方法及其核心思想;同时,对于本领域的一般技术人员,依据本申请的思想,在具体实施方式及应用范围上均会有改变之处,综上所述,本说明书内容不应理解为对本申请的限制。