本申请涉及计算机技术领域,特别涉及内存管理方法和装置。
背景技术:
计算机在执行任务时往往需要申请内存以存储数据,并在任务完成后释放这些内存,以避免造成内存泄露。
当这些任务处理的数据量骤增时,频繁的分配内存和释放内存的操作会大大增加系统开销,并且可能产生大量内存碎片,导致系统性能下降,降低程序的运行效率。
现有技术中,通常采用内存池技术来缓解频繁的内存分配和释放产生的系统开销。内存池技术是先从操作系统的内存空间分配一块内存,并将其划分为若干块固定大小的内存块,内存分配和内存释放都优先在内存池中进行。只有当内存池中的内存不够时,才调用操作系统的内存管理接口进行内存的分配和释放。
现有的内存池可以缓解操作系统频繁的申请内存和释放内存造成的系统性能消耗,但需要额外的内存空间来管理维护内存池中每一个内存块的空闲和使用情况。此外,由于通常采用固定大小的内存块,实际使用过程中要么限定于同一类数据结构的内存分配和释放(例如各个内存块大小相等),要么在内存分配时需要找到与实际使用内存大小最匹配的内存块予以使用(例如内存块的大小为2的幂次方),限制了应用范围。而且,在分配内存时,内存管理系统可能需要从多个内存块中查找适用的内存块,这也将产生一定开销。
由于上述缺陷,在例如高频次存取等的一些场景中,现有内存池技术难以令人满意。
技术实现要素:
有鉴于此,本申请提供适用于高频次存取等场景的内存管理方法和装置。
具体地,本申请是通过如下技术方案实现的:
一种内存管理方法,应用于内存管理系统,所述方法包括:
获取内存分配请求;
判断所述内存分配请求所请求的内存大小是否超过临时内存池的数据存储空间的未用部分的大小;
如果所请求的内存大小未超过所述临时内存池的数据存储空间的未用部分的大小,从所述临时内存池的数据存储空间的未用部分中分配所请求的内存,分配的内存的首地址为所述未用部分的首地址,并相应地更新所述临时内存池的数据存储空间的未用部分的大小和首地址,以及将临时内存池的已使用次数增加1。
一种内存管理装置,应用于内存管理系统,所述装置包括:
分配请求获取单元,用于获取内存分配请求;
第一判断单元,用于判断所述内存分配请求所请求的内存大小是否超过临时内存池的数据存储空间的未用部分的大小;
第一内存分配单元,如果所请求的内存大小未超过所述临时内存池的数据存储空间的未用部分的大小,用于从所述临时内存池的数据存储空间的未用部分中分配所请求的内存,分配的内存的首地址为所述未用部分的首地址,并相应地更新所述临时内存池的数据存储空间的未用部分的大小和首地址,以及将临时内存池的已使用次数增加1。
由以上本申请提供的技术方案可见,获取内存分配请求后,内存管理系统可判断所述内存分配请求所请求的内存大小是否超过临时内存池的数据存储空间的未用部分的大小;如果所请求的内存大小未超过所述临时内存池的数据存储空间的未用部分的大小,从所述临时内存池的数据存储空间的未用部分中分配所请求的内存,分配的内存的首地址为所述未用部分的首地址,并相应地更新所述临时内存池的数据存储空间的未用部分的大小和首地址,以及将临时内存池的已使用次数增加1。本技术方案中,优先使用临时内存池的数据存储空间,避免频繁通过操作系统的内存管理接口分配/释放空间而导致的系统性能下降;而且,相比于现有内存池方案,无需维护多个内存块的使用状况,管理临时内存池所需的额外开销非常少,此外还可灵活分配内存大小。因此,本方案非常适合频繁分配/释放内存等应用场景。
附图说明
图1为本申请示出的一种内存管理方法的流程图;
图2为本申请示出的一种临时内存池的数据存储空间的存储结构示例性示意图;
图3为本申请示出的另一种临时内存池的数据存储空间的存储结构示例性示意图;
图4为本申请示出的一种内存分配方法的示例性流程图;
图5为本申请示出的一种释放内存的方法的示例性流程图;
图6为本申请示出的一种内存管理装置。
具体实施方式
这里将详细地对示例性实施例进行说明,其示例表示在附图中。下面的描述涉及附图时,除非另有表示,不同附图中的相同数字表示相同或相似的要素。以下示例性实施例中所描述的实施方式并不代表与本申请相一致的所有实施方式。相反,它们仅是与如所附权利要求书中所详述的、本申请的一些方面相一致的装置和方法的例子。
在本申请使用的术语是仅仅出于描述特定实施例的目的,而非旨在限制本申请。在本申请和所附权利要求书中所使用的单数形式的“一种”、“所述”和“该”也旨在包括多数形式,除非上下文清楚地表示其他含义。还应当理解,本文中使用的术语“和/或”是指并包含一个或多个相关联的列出项目的任何或所有可能组合。
应当理解,尽管在本申请可能采用术语第一、第二、第三等来描述各种信息,但这些信息不应限于这些术语。这些术语仅用来将同一类型的信息彼此区分开。例如,在不脱离本申请范围的情况下,第一信息也可以被称为第二信息,类似地,第二信息也可以被称为第一信息。取决于语境,如在此所使用的词语“如果”可以被解释成为“在……时”或“当……时”或“响应于确定”。
请参见图1,图1为本申请示出的一种内存管理方法的流程图。
所述方法应用于内存管理系统。所述方法包括下列步骤102、104和106。
步骤102,获取内存分配请求。
计算机在执行许多任务时都需要占用一定内存空间用于存放数据,例如,在处理日志、处理数据报文等任务时。
步骤104,判断所述内存分配请求所请求的内存大小是否超过临时内存池的数据存储空间的未用部分的大小。
例如,设所述内存分配请求所请求的内存大小为len,所述临时内存池的数据空间的未用部分的大小为un_alloc,可比较二者大小。
步骤106,如果所请求的内存大小未超过所述临时内存池的数据存储空间的未用部分的大小,从所述临时内存池的数据存储空间的未用部分中分配所请求的内存,分配的内存的首地址为所述未用部分的首地址,并相应地更新所述临时内存池的数据存储空间的未用部分的大小和首地址,以及将临时内存池的已使用次数增加1。
如上所述,如果len不大于un_alloc,则从临时内存池的数据存储空间的未用部分的首地址开始分配所请求的数据。
例如,设临时内存池的数据存储空间的首地址为data,临时内存池的数据存储空间的总大小为size,已用部分的大小为alloc,则有size=un_alloc+alloc,并设未用部分的首地址为ptr。如上所述,如果len不大于un_alloc,则从临时内存池的数据存储空间的未用部分的首地址ptr开始分配长度为len的内存空间。
需要说明地是,因为一些参数是彼此相关、可以互相推导得出的,所以本领域技术人员可以理解,除非有明确相反理解,本文中更新参数a并非限定于一定直接存储参数a并直接对参数a进行更新,也可以是存储并更新与参数a相关的其他参数,以达到实际可获取和维护参数a的目的。例如,可以不直接存储临时内存池的数据存储空间的未用部分的首地址ptr,而是结合数据存储空间的地址信息和未用部分的大小un_alloc,得到未用部分的首地址ptr;甚至可以既不直接存储临时内存池的数据存储空间的未用部分的首地址ptr,也不直接存储未用部分的大小un_alloc,而是直接存储并更新已用部分的大小alloc,并结合数据存储空间的地址信息,可以很方便地得到所述未用部分的首地址ptr和大小un_alloc。细节可参见后文的相关描述。
在上述实施例中,获取内存分配请求后,内存管理系统可判断所述内存分配请求所请求的内存大小是否超过临时内存池的数据存储空间的未用部分的大小;如果所请求的内存大小未超过所述临时内存池的数据存储空间的未用部分的大小,从所述临时内存池的数据存储空间的未用部分中分配所请求的内存,分配的内存的首地址为所述未用部分的首地址,并相应地更新所述临时内存池的数据存储空间的未用部分的大小和首地址,以及将临时内存池的已使用次数增加1。本技术方案中,优先使用临时内存池的数据存储空间,避免频繁通过操作系统的内存管理接口分配/释放空间而导致的系统性能下降;而且,相比于现有内存池方案,本申请的技术方案无需维护多块内存的使用状况,且可灵活分配内存长度,大大减少了额外内存开销,并能灵活地适应多种数据的存储。因此,本方案非常适合频繁分配/释放内存等应用场景。
根据本申请,临时内存池的数据存储空间可以是连续的内存空间,也可以包括多个临时内存块,不同内存块间可以是不连续的,同一个内存块内部是连续的。
在一个示例中,所述临时内存池的数据存储空间为连续的内存空间。请参见图2,图2为本申请示出的一种临时内存池的数据存储空间的存储结构示例性示意图。图2所示的临时内存池的数据存储空间为连续的内存空间。在这种情况下,未用部分的首地址ptr=data+alloc,data表示数据存储空间的首地址,alloc表示数据存储空间的已用部分的大小。从未用部分的首地址ptr开始分配长度为len的内存空间,则所分配的内存空间为(data+alloc)~(data+alloc+len-1),如图2中阴影部分所示。相应地,在进行如图2所示的分配后,更新临时内存池的数据存储空间的未用部分的大小:un_alloc=un_alloc-len;更新临时内存池的数据存储空间的未用部分的首地址:ptr=ptr+len;更新临时内存池的已使用次数:count=count+1。
如前文所述,可以直接存储并更新未用部分的首地址ptr和大小un_alloc;也可以直接存储并更新un_alloc,而不直接存储ptr,并通过ptr=data+size-un_alloc-1得到对应的ptr;也可以不直接存储ptr和un_alloc,而是直接存储并更新alloc,通过ptr=data+alloc,un_alloc=size-alloc,得到ptr和un_alloc。。
在一个示例中,所述临时内存池的数据存储空间包括多个临时内存块。请参见图3,图3为本申请示出的一种临时内存池的存储结构示例性示意图。图3所示的临时内存池的数据存储空间包括地址范围分别为1024~2047和4096~5119的两个临时内存块,并设已用部分的大小alloc为512,对应地,未用部分的大小un_alloc为1536、未用部分的首地址ptr为1536。
设内存分配请求所请求的内存大小为1024,由于所请求的内存大小1024小于未用部分的大小为1536,则可从未用部分的首地址ptr1536开始分配1024大小的内存,则所分配的内存空间为1536~2047以及4096~4607,如图3中阴影部分所示。更新后的临时内存池的数据存储空间的未用部分的大小un_alloc为512,更新后的临时内存池的数据存储空间的未用部分的首地址ptr为4608,并将临时内存池的已使用次数count增加1。
同样地,如上所述,因为参数间具有一定相关性,所以本领域技术人员可以理解,此处更新参数并非限定于一定直接存储该参数并直接对该参数进行更新。例如,如图3所示的示例中,可以直接存储并更新临时内存池的数据存储空间的已用部分的大小alloc,并结合所存储的临时内存池的数据存储空间的地址范围,来实现获取和更新un_alloc以及ptr的目的。
可以看出,无论临时内存池的数据存储空间是连续的内存空间还是由多个分隔开的临时内存块组成,都可仅通过少量参数即实现对临时内存池的数据存储空间使用情况的管理和维护。
在一种可能的实施方式中,所述方法还可以包括:
如果所请求的内存大小超过所述临时内存池的数据存储空间的未用部分的大小,调用操作系统内存分配接口以分配所请求的内存。
请参见图4,图4为本申请示出的一种内存分配方法的示例性流程图。在本示例中,设临时内存池占用了连续的内存空间。
如图4所示,在步骤402,获取内存分配请求,设其请求分配大小为len的内存。在步骤404,判断所述内存分配请求所请求的内存大小len是否超过临时内存池的数据存储空间的未用部分的大小un_alloc。设本示例中,直接存储并更新的参数是数据存储空间的已用部分的大小alloc,则可通过un_alloc=size(数据存储空间的总大小)-alloc得到未用部分的大小。
如果步骤404的判断结果是肯定的,则进入步骤406,调用操作系统内存分配接口从系统内存中分配大小为len的内存。虽然临时内存池实质上仍然是系统内存的一部分,但此处步骤406中提到的系统内存不包括已被用作临时内存池的内存空间。
如果步骤404的判断结果是否定的,则进入步骤408。在步骤408,从临时内存池的数据存储空间的未用部分的首地址开始,分配大小为len的内存,即返回data(数据存储空间的首地址)+alloc作为所分配的内存的首地址,并更新alloc和count:alloc=alloc+1,count=count+1。
在一种可能的实施方式中,所述方法还包括:
获取内存释放请求;
判断所述内存释放请求所请求释放的内存的首地址是否超出临时内存池的数据存储空间的已用部分的地址范围;
如果所请求释放的内存的首地址未超出所述临时内存池的数据存储空间的已用部分的地址范围,将临时内存池的所述已使用次数减1。
在一种可能的实施方式中,所述方法还包括:
如果所请求释放的内存的首地址超出所述临时内存池的数据存储空间的已用部分的地址范围,调用操作系统内存释放接口以释放所请求释放的内存。
在一种可能的实施方式中,所述方法还包括:
如果所请求释放的内存的首地址超出所述临时内存池的数据存储空间的已用部分的地址范围,调用操作系统内存释放接口以释放所请求释放的内存。
请参见图5,图5为本申请示出的一种释放内存的方法的示例性流程图。在步骤502,获取内存释放请求。在步骤504,判断所请求释放的内存首地址是否超出临时内存池的数据存储空间的已用部分的地址范围。如上所述,如果所述临时内存池的数据存储空间为连续的内存空间,则判断所请求释放的内存的首地址是否在data~data+alloc-1的范围内,其中data表示所述数据存储空间的首地址,alloc表示所述数据存储空间的已用部分的大小;如果所述临时内存池的数据存储空间包括多个分隔的内存块,则所述数据存储空间的已用部分的地址范围可能包括多个地址段,具体通过所述数据存储空间的地址范围和已用部分的大小alloc可以较为容易地算出这些地址段。
如果步骤504的判断结果是肯定的,则进入步骤506,调用操作系统内存释放接口从系统内存中释放所请求释放的内存。
如果步骤504的判断结果是否定的,则进入步骤508,将临时内存池的所述已使用次数count减1:count=count-1。可以注意到,此处更新了count,而未更新已用部分和/或未用部分的大小、未用部分的首地址等参数,从而便于在后续分配临时内存池的数据存储空间中的内存时按地址依序向后分配,而不涉及所述数据存储空间中已被释放的内存块,进一步简化了对临时内存池的管理维护,有利于显著减少额外开销。
在步骤510,判断临时内存池的已使用次数count是否为零。如果判断结果是否,则认为所述临时内存池的数据存储空间仍处在被使用状态;如果判断结果是肯定的,则进入步骤512。
在步骤512,可将所述临时内存池的数据存储空间未用部分的大小和首地址恢复为所述数据存储空间为空闲状态时的初始值。已使用次数count回到零,可认为所述来临时内存池已处于空闲状态,即之前被使用的内存都已被释放,则此时,可将未用部分的大小un_alloc设置为数据存储空间的总大小size,未用部分的首地址设置为整个数据存储空间的首地址data。当然如上所述,可能不直接存储un_alloc和/或data,而是直接存储数据存储空间的已用部分的大小alloc,则将alloc设置为零。
在一种可能的实施方式中,在上述内存分配/释放之前,所述方法还包括:
调用操作系统内存分配接口以分配存储空间作为所述临时内存池;
在所述临时内存池的参数存储空间存储并初始化下列参数中的部分或全部:数据存储空间的首地址,数据存储空间的总大小,数据存储空间的地址范围,数据存储空间的未用部分的大小,数据存储空间的已用部分的大小,临时内存池的已使用次数。
上述步骤可被视为一种可能的临时内存池初始化方法。如前文所述,所述临时内存池可以是连续的,也可以包括多个彼此分隔的数据块。如前文所述,由于参数之间的相关性,在参数存储空间可以只直接存储上述部分参数,而所需的其他参数可以通过直接存储的参数推导而来;当然,也可直接存储上述全部参数。占用连续内存空间的临时内存池和由彼此分隔的多个内存块组成的临时内存池所需的参数可能略有不同。但从上文可以看出,无论是哪种情况,参数存储空间所要直接存储和维护的参数都很少,所占的内存空间很小,几乎可以忽略不计。
请参见图6,图6为本申请示出的一种内存管理装置。所述内存管理装置应用于内存管理系统。所述装置包括分配请求获取单元602、第一判断单元604、第一内存分配单元606。
分配请求获取单元602,用于获取内存分配请求。
第一判断单元604,用于判断所述内存分配请求所请求的内存大小是否超过临时内存池的数据存储空间的未用部分的大小。
第一内存分配单元606,如果所请求的内存大小未超过所述临时内存池的数据存储空间的未用部分的大小,用于从所述临时内存池的数据存储空间的未用部分中分配所请求的内存,分配的内存的首地址为所述未用部分的首地址,并相应地更新所述临时内存池的数据存储空间的未用部分的大小和首地址,以及将临时内存池的已使用次数增加1。
在一种可能的实施方式中,所述装置还可以包括:
第二内存分配单元,如果所请求的内存大小超过所述临时内存池的数据存储空间的未用部分的大小,用于调用操作系统内存分配接口以分配所请求的内存。
在一种可能的实施方式中,所述装置还可以包括:
释放请求获取单元,用于获取内存释放请求;
第二判断单元,用于判断所述内存释放请求所请求释放的内存的首地址是否超出临时内存池的数据存储空间的已用部分的地址范围;
第一内存释放单元,如果所请求释放的内存的首地址未超出所述临时内存池的数据存储空间的已用部分的地址范围,用于将临时内存池的所述已使用次数减1。
在一种可能的实施方式中,所述装置还可以包括:
第一参数初始化单元,用于当所述临时内存池的所述已使用次数减少为0时,将所述临时内存池的数据存储空间未用部分的大小和首地址恢复为所述数据存储空间为空闲状态时的初始值。
在一种可能的实施方式中,所述装置还可以包括:
第二内存释放单元,如果所请求释放的内存的首地址超出所述临时内存池的数据存储空间的已用部分的地址范围,用于调用操作系统内存释放接口以释放所请求释放的内存。
在一种可能的实施方式中,所述装置还可以包括:
临时内存池分配单元,用于调用操作系统内存分配接口以分配存储空间作为所述临时内存池;
第二参数初始化单元,用于在所述临时内存池的参数存储空间存储并初始化下列参数中的部分或全部:数据存储空间的首地址,数据存储空间的总大小,数据存储空间的地址范围,数据存储空间的未用部分的大小,数据存储空间的已用部分的大小,临时内存池的已使用次数。
上述装置中各个单元的功能和作用的实现过程具体详见上述方法中对应步骤的实现过程,在此不再赘述。
对于装置实施例而言,由于其基本对应于方法实施例,所以相关之处参见方法实施例的部分说明即可。以上所描述的装置实施例仅仅是示意性的,其中所述作为分离部件说明的单元可以是或者也可以不是物理上分开的,作为单元显示的部件可以是或者也可以不是物理单元,即可以位于一个地方,或者也可以分布到多个网络单元上。可以根据实际的需要选择其中的部分或者全部模块来实现本申请方案的目的。本领域普通技术人员在不付出创造性劳动的情况下,即可以理解并实施。
以下以高性能日志服务器的日志解析为例,对本申请的技术方案的有益效果进行进一步说明。
高性能日志服务器每时每刻都在处理海量日志,处理过程包括日志的解析、存储、查询等操作。
以解析1000万条日志、每条日志有10个字段为例。假设每个字段都需要解析,即需要为每个字段申请内存用于存放解析后的数据,这样1000万条日志的解析过程,就需要有1亿次内存申请和释放(1000万条*10个字段),这对于现有技术的内存池方案,需要维护1亿次内存分配和内存释放的管理工作,这就是变成了不容忽视的开销。对于内存分配来说,找到可用的空闲内存就是开销;对于内释放来说,将空闲内存放到空闲内存区就是开销。
应用本申请的技术方案,可以在解析这1000万条日志前,预先初始化临时内存池。申请的临时内存池可包括参数存储空间和数据存储空间。参数存储空间所占的空间非常小,可能只需几个字节,可以忽略不计。参数存储空间中存储的参数此时都设置为初始值。一些参数是全程不变的,例如临时内存池的数据存储空间的首地址、总大小等,一些参数是后续随着分配/释放内存而相应更新的,例如临时内存池的数据空间的已用部分/未用部分的大小,临时内存池的已使用次数等,其中,临时内存池的数据空间的已用部分/未用部分的大小在分配内存时更新,在释放内存时不更新,除非释放内存时出现已使用次数减为0的情况。可根据解析-条日志的10个字段所需要的内存大小来确定数据存储空间的大小。
在解析某一条日志时,为待解析的字段从临时内存池中申请内存用于存放解析后的字段。由于分配的内存空间的首地址ptr可直接确定,无需如现有内存池技术一样查找可用的空闲内存,所以开销可以忽略不计。待解析后的字段不再使用时即可将释放内存,还给临时内存池。在内存分配和释放中要更新的参数都非常有限,可能只需更新一个或两个参数,开销可以忽略不计。
直至所有字段解析的数据都使用完毕时,所有曾被占用的内存都归还给了临时内存池,这时临时内存池的已使用次数被减到了零,临时内存池又恢复到初始状态。就这样,利用临时内存池循环解析处理1000万条日志。
在此过程中完成了1亿次内存申请和释放工作量,而采用本申请的技术方案实现这1亿次的内存申请和释放的工作量,要远远低于现有技术的通用内存池技术所带来的性能开销。针对高频率处理一组数据这类应用场景,本申请相对现有通用内存池技术具有显著优势。可以看出,本申请的技术方案尤其适用于内存生命周期短且使用频率高的应用场景。
以上所述仅为本申请的较佳实施例而已,并不用以限制本申请,凡在本申请的精神和原则之内,所做的任何修改、等同替换、改进等,均应包含在本申请保护的范围之内。