首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

【技术探究】一种基于虚构单元可智能增长的内存池研究

2012-09-06 
【技术探究】一种基于虚拟单元可智能增长的内存池研究1、引言:随着科学技术的发展,新的应用需求和客观应用条

【技术探究】一种基于虚拟单元可智能增长的内存池研究

1、引言:

        随着科学技术的发展,新的应用需求和客观应用条件的成熟使得内存数据库(MMDB)应运而生。内存数据库将数据库的工作版本放在内存中,大部分操作都在内存中进行,从而磁盘 I/O 不再是内存数据库的瓶颈,如何提高数据库的效率和存储空间的利用率成为了内存数据库的设计目标。

        在内存数据库中,大量的数据存取和事务处理使得内存频繁的进行分配和回收。而数据库中最常见的对象——数据集又是以不定长的形式存在,小到十几字节,大到几十几百字节。大量小型数据集空间的申请/释放极易产生内存碎片,从而导致存储空间的浪费并使得系统在内存分配时将大部分的时间消耗在寻找适宜内存块上。因此,在内存数据库系统中,选择正确的内存空间动态管理策略以减少碎片数量,提高空间利用率,是系统性能提升的关键。目前内存数据库主要采用的的内存管理方案有位图分配法和内存池两种。

2、传统内存池技术及其存在的缺陷  

        内存池(Memory Pool)是用来解决内存频繁分配和释放问题的首选方法。通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片进而降低性能。而内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等的内存块留作备用。当有新的内存需求时,就从内存池中取出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。

       传统的内存池主要由三层结构组成(如图1),第一层为内存池初始化时通过new方法申请的大块内存(Memory Chunk);第二层是用于满足不同大小的内存分配请求的链表;第三层则是一定数量的不同大小的内存节点(node)。内存池采用双向链表的方式组织内存块和内存节点,块与块之间,节点与节点之间都通过指针相连,未分配的节点由空闲链表维护。当需要申请内存时,从对应大小的空闲链表中取出一个节点返回给申请者;当节点使用完毕需要释放时,回收的节点将被挂载到对应空闲列表的表头或尾部,等待下次分配。

【技术探究】一种基于虚构单元可智能增长的内存池研究

        由于传统内存池结构简单,在分配/回收内存时只需简单的移动指针,通常情况下时间复杂度为O(1),仅在内存块耗尽,需要调用new函数向堆申请新的内存块时才会产生额外开销。然而,尽管在时间性能上表现优异,传统内存池在空间利用上却存在一定缺陷。由内存节点的成员变量组成的头部将会占用一定大小节点空间,对于较小的节点,头部的大小几乎和数据区大小相当,造成了节点空间的浪费。举一个例子,当有1000万个8字节数据区大小的节点被分配时,用于存储数据的空间为8B×10^7=80MB,而用于存储节点的双向指针的空间同样为8B×10^7=80MB,加上其他变量所占空间,实际空间利用率不足50%。当内存数据库应用于内存容量较小的移动终端设备时,这样低的空间利用率是不能接受的。此外,传统内存池缺少合理的内存块增长控制策略和异常恢复机制,当出现内存不足,无法满足分配请求的情况时,系统将陷入瘫痪。可见,传统内存池尽管拥有不错的时间性能,但在空间利用率和健壮性方面,远远不能满足内存数据库系统的需要。

3、基于虚拟单元可智能增长的内存池技术

        本文提出了一种新型的基于虚拟单元智能增长的内存池SVMP(Smart-growth & Virtual-unit -based Memory Pool),在继承了传统内存池的优点之余,改进了内存分配/回收机制,为提高空间利用率提出了虚拟单元(Virtual-unit)的概念,并设计了智能增长算法(Smart-growth Algorithm)用于解决内存池的增长问题。

3.1 设计核心和层级结构    

        SVMP技术的核心是虚拟单元和智能增长算法。虚拟单元本身并不存在,只是通过游标移动,将前后两次移动的间隔长度大小的内存区称为一个单元,是一种完全逻辑意义上的划分。由于虚拟单元不具备物理结构,尽可能多的内存空间将被用作数据区,从而极大的提高了内存的空间利用率。智能增长算法以TCP模型中拥塞控制的AIMD思想为核心,对内存池的增长进行合理控制,减少了直接调用new函数的次数,并通过C++的new-handler机制处理多次申请后产生的内存不足的问题。

       SVMP在层级结构上继承了传统内存池的池-表-块三层设计,但又有所区别(图2)。针对数据集不定长的特点,第一层的池结构sv_mem_pool初始化了128个unit_size分别为8字节~1024字节大小的的链表,以指针数组list_collection[NUM_OF_LIST]索引,能够在较小粒度上提供内存。第二层的链表sv_mem_list以单向指针连接第三层的内存块,其中head_chunk指针指向该链表的第一个内存块,current_chunk指针则指向当前正在用于分配的内存块,此外还拥有一个缓冲栈free_ stack,负责对应大小的虚拟单元的回收。第三层的sv_ mem_chunk(图3)在设计上放弃了传统内存池的node结构和空闲链表,而是直接向堆申请一块连续内存空间作为数据区,然后根据链表中指定的unit_size将内存空间划分为n个虚拟单元,游标cursor_pos指向的虚拟单元即为下一次将被分配的单元。

 【技术探究】一种基于虚构单元可智能增长的内存池研究

 

3.2 内存分配/回收策略

        SVMP在传统内存池的基础上改进了内存的分配回收策略,使得其能够更好的应用于内存数据库系统。

        SVMP支持8~1024字节的分配请求,如果申请的空间大小超过上限MAX_BYTES=1024字节,则将这种大块空间的分配返回给操作系统处理。当提出内存申请请求时,由于不同的链表维护的虚拟单元的上调边界ALIGN=8字节,如果分配的空间达不到8字节大小,将按照8字节分配,如果需要的空间超过8字节,则将分配的空间上调为8字节的倍数,即用ALIGN整除申请的空间大小,以此索引list_collection中维护对应虚拟单元的链表。在索引到正确的链表后,首先查看缓冲栈free_stack中是否为空,如果free_stack中存在指向已回收的虚拟单元的指针,则将指针弹出栈并返回,该虚拟单元再次被利用,分配结束;如果free_stack为空,将申请提交当前内存块current_chunk,检查current_ chunk是否存在虚拟单元可供分配,如果存在,则将cursor_pos指向的虚拟单元地址返回给用户,并将cursor_pos移动到指向下一个虚拟单元,分配结束;否则链表将构造新的内存块,调用全局new函数向堆申请新的内存空间,current_chunk指针将指向新构造的块,并返回新申请块的第一个虚拟单元,分配结束。

        当释放内存时,首先仍需索引list_collection中维护待回收虚拟单元的链表,再将指向该单元的指针压入free_stack,回收完毕。

【技术探究】一种基于虚构单元可智能增长的内存池研究

3.3 智能增长算法

        在增长算法的设计上,SVMP受到了TCP/IP模型中解决拥塞控制的AIMD(Additive Increase Multipli- cative Decrease)算法的启发。AIMD算法是TCP/IP模型中,运输层为解决拥塞控制的一种方法,即:加性增,乘性减,或者叫做“和式增加,积式减少”。当TCP发送方感受到端到端路径无拥塞时就线性的增加其发送窗口长度,当察觉到路径拥塞时就乘性减小其发送窗口长度。

        SVMP在初始化时所有链表向堆申请一定大小的内存块,随着系统运行时间增长,处理的数据增多,将会出现没有虚拟单元可供分配的情况,必须再次向堆申请内存空间。在SGI STL的allocator设计中,当没有空闲节点可用时,默认每次返回新的定长的20块内存节点,这种每次新增同样大小内存块的方式虽然简单,但无法较好的适应持续增长的数据区请求,SVMP中为了减少直接调用new函数的次数,当需要再次申请内存块时,SVMP将在之前内存块大小的基础上进行扩容。用M表示新申请的块容量,M'表示前一次申请的块容量,V表示初始化时申请的内存块容量,则:

M=M'+V=nV(n表示申请内存块的次数)。

M的大小也不可能无限量增加,当到达既定的最大上限MAX_SIZE(1000个页大小4MB)时,以后新申请的内存块容量跟之前的块将保持一致。

算法实现如下:

内存管理方式

消耗时间/s

传统内存池

0.067

SVMP

0.034

new/delete

0.593

表1:三种不同内存管理方式的运行时间对比

        表2是分别使用传统内存池和SVMP以及直接调用new/delete这三种不同的内存管理方式消耗的内存空间大小数据。存储相同大小的数据量,传统内存池消耗了1.2GB内存空间,SVMP消耗了722MB内存空间,直接调用new/delete消耗了748MB内存空间。SVMP的虚拟单元结构和智能增长算法使得内存空间利用率较传统内存池提升了一个层次,与直接直接调用new/delete消耗的内存空间基本相当。

内存管理方式

消耗内存/MB

传统内存池

1273

SVMP

722

new/delete

748

表2:三种不同内存管理方式消耗内存空间对比

5、结语   

       SVMP吸收了传统内存池的优点,改进了内存分配/回收策略,利用虚拟单元提高了空间利用率,同时依然具备良好的时间性能。此外,SVMP具备智能增长特性,并为内存不足的情况设定了恢复机制,具有较强的健壮性,十分适用于内存数据库系统。

3楼woshinia前天 18:25
”第二层的链表sv_mem_list以单向指针连接第三层的内存块,其中head_chunk指针指向该链表的第一个内存块,current_chunk指针则指向当前正在用于分配的内存块,此外还拥有一个缓冲栈free_ stack,负责对应大小的虚拟单元的回收。“nfree_ stack是栈的话,跟传统的双向链表几乎没什么区别吧。如果是频繁的分配和释放的话,基本就是入栈和出栈的操作,那么游标的优势也就只有开始的时候有一点,基本可以忽略了。
Re: yuyu2223前天 18:33
回复woshinian游标和虚拟单元的设计主要是注重空间的利用,时间上提升的并不太多。传统内存池是以节点作为分配单位,需要链表维护,我这个是以虚拟单元为分配单位,是直接将数据区分配出去,还是有很大区别的。可能是你没有看的太仔细,也可能是我没有讲的太清楚。 不过也欢迎你的发言~
2楼liutengteng1303天前 08:12
学习了。
Re: yuyu2223前天 16:40
回复liutengteng130n见笑了,欢迎讨论,共同进步。
1楼yuyu22233天前 01:22
欢迎留言讨论

热点排行