一种内存管理装置和方法与流程

文档序号:11154209阅读:234来源:国知局
一种内存管理装置和方法与制造工艺

本发明涉及数据存储领域,更具体地说,涉及一种内存管理装置和方法。



背景技术:

提高硬盘写入IO的方式无疑是批量顺序写,无论是在业界轮行的分布式文件系统或数据,HBase,GFS和HDFS,还是以磁盘文件为持久化方式的消息队列Kafka都采用了在内存缓存数据然后再批量写入的策略。这一个策略的性能核心就是内存中缓冲区的设计。然而,为了满足读写同步,必须要保证:(1)写满不写;(2)读空不读(3)不丢失数据(4)不读重复数据。为了达到这一目的,最常用的方式是JDK自带的LinkedBlockingQueue,是一个带锁的消息队列,写入和读出时加锁,在满足以上条件时,却占用了极大的系统资源,成为很多对吞吐量要求很高的程序的性能瓶颈。



技术实现要素:

本发明要解决的技术问题在于如何避免系统资源的过多占用,且保证足够的读写速度;针对该技术问题,提供一种内存管理装置,包括:

创建模块,用于创建定长数组,为定长数组的各元素分配存储空间,所述定长数组使用环形队列数据结构;

设置模块,用于设置一个基于所述环形队列的用于标识下一写入位置的标识指针;

写数据模块,用于当写数据时,通过竞争获取所述标识指针,向所述标识指针对应的写入位置写入数据;使所述标识指针跳转到下一写入位置,释放所述标识指针;

读数据模块,用于当读数据时,基于所述环形队列依次顺序读取数据,并更新当前读取位置;

确保模块,用于在所述写数据和读数据的过程中,确保所述标识指针与所述当前读取位置处于环形队列中的不同位置。

可选的,所述定长数组的元素的数量为2的指数倍。

可选的,所述写数据模块还用于:通过多线程分别执行CAS控制指令竞争获取所述标识指针。

可选的,所述确保模块还用于:

设置一个大于等于1的写操作等待阈值;

在写数据时,当写位置差值小于等于所述写操作等待阈值时,暂停写数据操作,所述写位置差值为所述标识指针沿着环形队列的数据方向上与所述当前读取位置之间的位置差值;

监控所述写位置差值,并在所述写位置差值大于所述写操作等待阈值时重启写数据操作。

可选的,所述确保模块还用于:

设置一个大于等于1的读操作等待阈值;

在读数据时,当读位置差值小于等于所述读操作等待阈值时,暂停读数据操作,所述读位置差值为所述当前读取位置沿着环形队列的数据方向上与所述标识指针之间的位置差值;

监控所述读位置差值,并在所述读位置差值大于所述读操作等待阈值时重启读数据操作。

此外,还提供一种内存管理方法,包括:

创建定长数组,并为定长数组的各元素分配存储空间,所述定长数组使用环形队列数据结构;

设置一个基于所述环形队列的用于标识下一写入位置的标识指针;

当写数据时,通过竞争获取所述标识指针,向所述标识指针对应的写入位置写入数据;使所述标识指针跳转到下一写入位置,释放所述标识指针;

当读数据时,基于环形队列依次顺序读取数据,并更新当前读取位置;

在所述写数据和读数据的过程中,确保所述标识指针与所述当前读取位置处于环形队列中的不同位置。

可选的,所述定长数组的元素的数量为2的指数倍。

可选的,所述当写数据时,通过竞争获取所述标识指针包括:通过多线程分别执行CAS控制指令竞争获取所述标识指针。

可选的,所述在写数据过程中,确定所述标识指针与所述当前读取位置处于环形队列中的不同位置包括:

设置一个大于等于1的写操作等待阈值;

在写数据时,当写位置差值小于等于所述写操作等待阈值时,暂停写数据操作,所述写位置差值为所述标识指针沿着环形队列的数据方向上与所述当前读取位置之间的位置差值;

监控所述写位置差值,并在所述写位置差值大于所述写操作等待阈值时重启写数据操作。

可选的,所述在读数据过程中,确定所述标识指针与所述当前读取位置处于环形队列中的不同位置包括:

设置一个大于等于1的读操作等待阈值;

在读数据时,当读位置差值小于等于所述读操作等待阈值时,暂停读数据操作,所述读位置差值为所述当前读取位置沿着环形队列的数据方向上与所述标识指针之间的位置差值;

监控所述读位置差值,并在所述读位置差值大于所述读操作等待阈值时重启读数据操作。

有益效果

本发明提供了一种内存管理装置和方法,创建定长数组,为定长数组的各元素分配存储空间,定长数组使用环形队列数据结构,设置一个基于环形队列的用于标识下一写入位置的标识指针;当写数据时,通过竞争获取标识指针,像标识指针对应的写入位置写入数据,读数据时,基于环形队列依次顺序读取数据,在读写的过程中,确保标识指针和当前读取位置处于环形队列中的不同位置。通过本发明的实施,使用标识指针来进行数据的写入,且保证读写过程中标识指针和当前写入位置不重叠,从而满足了读写同步,节约了大量的系统资源。

附图说明

下面将结合附图及实施例对本发明作进一步说明,附图中:

图1为本发明第一实施例提供的一种内存管理装置组成示意图;

图2为本发明第一实施例提供的一种环形队列示意图;

图3为本发明第二实施例提供的一种写位置差值的表现方式示意图;

图4为本发明第二实施例提供的一种读位置差值的表现方式示意图;

图5为本发明第三实施例提供的一种内存管理方法流程图;

图6为本发明第四实施例提供的一种内存管理方法流程图。

具体实施方式

应当理解,此处所描述的具体实施例仅仅用以解释本发明,并不用于限定本发明。

第一实施例

请参考图1,图1为本发明第一实施例提供的一种内存管理装置组成示意图,包括:

创建模块101,用于创建定长数组,为定长数组的各元素分配存储空间,该定长数组使用环形队列数据结构;

设置模块102,用于设置一个基于环形队列的用于标识下一写入位置的标识指针;

写数据模块103,用于当写数据时,通过竞争获取标识指针,向标识指针对应的写入位置写入数据;使标识指针跳转到下一写入位置,释放标识指针;

读数据模块104,用于当读数据时,基于环形队列依次顺序读取数据,并更新当前读取位置;

确保模块105,用于在写数据和读数据的过程中,确保标识指针与当前读取位置处于环形队列中的不同位置。

本实施例中的定长数组使用环形队列数据结构,环形队列是在实际编程中极为有用的数据结构,它有如下特点:

它是一个首尾相连的FIFO(First In First Out,先进先出)的数据结构,采用数组的线性空间,数据组织简单。能很快知道队列是否是满或是空。能以很快的速度来存取数据。

因为简单高效的原因,甚至在硬件上都实现了环形队列。

环形队列广泛应用于网络数据收发,和不同程序间数据交换(比如内核与应用程序大量交换数据,从硬件接收大量数据)均使用了环形队列。

实际上,内存并没有环形结构,因此环形队列实际上是数组的线性空间来实现。当数据到了尾部时,它将回到0位置处理。这个转回是通过取模操作来执行的。因此,环形队列逻辑上是将数组元素q[0]与q[n-1]连接,形成一个存放队列的环形空间。请参考图2,图2示出了一种具有八个元素的环形队列形态的定长数组,其中q[n-1]即为q[7]。

在实际使用中,环形队列并没有首尾之分,由于首尾相接,环形队列中所存储的数据也没有前后的区别;然而,环形队列的数据读写是有一定的方向的,虽然这个方向对于不同的环形队列而言是不一定的,但是对于某个特定的环形队列而言,这个方向是唯一确定的;用户所写入的数据是以这个确定的方向写入,用户读取数据也同样是以这个确定的方向进行读取。

定长数组的含义在于,数组的长度,或者说数组中允许存取元素的空间的数量是固定的;请继续参考图2,图2所示出的环形数组,其数组的长度是8,数组中允许存取元素的空间的数量也是8,以其中任意一个存取元素的空间作为起始元素q[0],以特定方向,图2中的为逆时针方向,各元素的编号分别为q[1]、q[2]、q[3]、q[4]、q[5]、q[6]、q[7];当定长数组的长度不是8,是更大或者更小的数时,与为8的情况类似;如不特殊说明,本实施例中所列举的定长数组的长度均是8。

设置模块102用于设置一个基于该环形队列的标识指针,用于标识下一写入位置。在本实施例中,在定长数组中写入数据是通过标识指针来指引的,即写入数据是在标识指针所在的位置写入;标识指针的逻辑是,在当前的位置写完数据后,会进行自增,即在环形队列的写数据方向上自行移动,然后,在标识指针所处的新的位置上继续写入数据。标识指针所占用的系统资源极少,且无需用户自行操作,它会自动在环形队列中移动。

写数据模块103用于当写数据时,通过竞争获取标识指针,向标识指针对应的写入位置写入数据。当不止一个数据要写入时,在同一个存储位置一般只存储一个对象写入的数据,那么,不同的对象之间就需要通过竞争,来获取标识指针,或者说获取标识指针的使用权,使该对象能够在标识指针所在的位置写入数据。

在当前位置的数据写完之后,标识指针跳转到下一写入位置,释放标识指针。其中,释放标识指针,或者说释放标识指针的控制权,在前一次的数据写入完成后,释放的标识指针会自动的沿着数据写入的方向跳转到下一写入位置,等待下一数据的写入。

读数据模块104用于当读数据时,基于环形队列依次顺序读取数据,并更新当前读取位置。基于环形队列依次顺序读取数据,指的就是在环形队列中,数据的读取是按照一个特定的方向来的,对于一个特定的环形队列而言,这个方向是确定的,与写数据的方向一致。

确保模块105,用于在写数据和读数据的过程中,确定标识指针和当前读取位置处于环形队列中的不同位置。由于在数据读写的过程中,有着写满不写,读空不读的要求,即环形队列中即将在下一个位置写数据时,该下一个位置的数据仍然未被读取,那么就不应再写;以及在环形队列中,即将读取下一位置的数据时,下一位置的数据为空或者尚未写完,那么就不应再读。如果在下一位置的数据仍未被读取时写入数据的话,那么就会导致数据丢失;如果在下一位置的数据为空或者尚未写完时读取数据的话,就会读取到空的数据,浪费系统资源和时间。

而正常而言,数据读写的过程中,一个数据总是先被写入之后,再被读取,换言之,对于一个数据而言,写入在先,读取在后,在环形队列中,总是先写的数据先被读取,那么,在满足写满不写,读空不读时,标识指针和当前读取位置总是处于环形队列中的不同位置的。

本实施例提供了一种内存管理装置,包括创建模块、设置模块、写数据模块、读数据模块以及确保模块,通过实施例的实施,实现了使用标识指针来进行数据的写入,且保证读写过程中标识指针和当前写入位置不重叠,满足和读写同步,节约了大量的系统资源。

第二实施例

请继续参考图1,图1为本发明第二实施例提供的一种内存管理装置组成示意图,包括:

创建模块101,用于创建定长数组,为定长数组的各元素分配存储空间,该定长数组使用环形队列数据结构;

设置模块102,用于设置一个基于环形队列的用于标识下一写入位置的标识指针;

写数据模块103,用于当写数据时,通过竞争获取标识指针,向标识指针对应的写入位置写入数据;使标识指针跳转到下一写入位置,释放标识指针;

读数据模块104,用于当读数据时,基于环形队列依次顺序读取数据,并更新当前读取位置;

确保模块105,用于在写数据和读数据的过程中,确保标识指针与当前读取位置处于环形队列中的不同位置。

其中,在本实施例中,关于定长数组的大小的选择方面有一定的要求,由于在环形队列中会用到取余操作,在大部分处理器上,取余操作并不高效,因此,在本实施例中,定长数组的元素的数量为2的指数倍,这样,计算余数只需要通过为操作index&(size-1)就能够得到实际的index。对外只有一个变量,那就是队尾元素的下标:cursor,这也避免了对head/tail这两个变量的操作和协同。

在本实施例中,写数据模块103还用于:通过多线程分别执行CAS控制指令竞争获取标识指针。在实际写数据的过程中,在同一时间可能并不止有一个即将执行的写入操作,即进行写操作的对象并不止一个;如果两个或以上的对象同时都想写入数据,则他们会同时执行CAS指令,具体为CAS(slot,slot+1),然后执行成功的竞争成功,获取标识指针,或者说是获取标识指针对应的写入位置的存储权,获取该存储权的对象就可以将数据写入,其他的未获取成功的则需要继续下一个CAS指令申请之后的标识指针。在这一过程中,一般并不需要用到锁,使用的是系统的CAS指令。

在很多时候会有多个对象去抢数组上的同一个位置,在一般的java程序中,是通过加锁来实现,但本实施例是通过CAS来实现的,多个会去竞争,但不会存在两个同时抢到,抢不到的就抢下一个位置。读写双方都要检查对方的位置,防止超过对方。在本实施例中,检查的策略可以包括主动检查,比如按照一定的时间间隔周期性的检查对方的位置,或者等待对方的通知,如设置一道指令,令对方读/写到环形队列的某一位置即发送通知。

在本实施例中,确保模块105还用于:设置一个大于等于1的写操作等待阈值;

在写数据时,当写位置差值小于等于写操作等待阈值时,暂停写数据操作,其中,写位置差值为标识指针沿着环形队列的数据方向上与当前读取位置之间的位置差值;

监控写位置差值,并在写位置差值大于写操作等待阈值时重启写数据操作。

也就是说,确保模块105为了确保在写数据时,确保标识指针与当前读取位置处于环形队列中的不同位置,首先,设置一个大于等于1的写操作等待阈值,而写位置差值则是标识指针,在沿着环形队列的数据方向上与当前读取位置之间的位置差值;通俗的讲,就是标识指针与当前读取位置之间的间隔,而这个间隔是从标识指针到下一写入位置方向上所得的,请参考图3,图3示出了一种写位置差值的计算方式,或者说是表现方式。从图3中可以看出,读数据的方向和写数据的方向是一致的,当写数据的速度过快时,标识指针的位置就可能达到或者超过当前读取位置。因此,设置一个写操作等待阈值,这个阈值至少为1,即标识指针与当前读取位置之间至少间隔一个位置,而具体的写操作等待阈值可以基于环形队列的长度、数据量的大小、读写的速度等等参数进行设置;当标识指针所处的位置与当前读取位置之间的差值小于或等于写操作等待阈值时,暂停写数据操作,即不再进行写数据操作;与此同时,实时监控写位置差值,在写位置差值大于写操作等待阈值时,重启写数据操作。

在本实施例中,确保模块105还用于:设置一个大于等于1的读操作等待阈值;

在读数据时,当读位置差值小于等于读操作等待阈值时,暂停读数据操作,其中,读位置差值为当前读取位置沿着环形队列的数据方向上与标识指针之间的位置差值;

监控读位置差值,并在读位置差值大于读操作等待阈值时重启读数据操作。

也就是说,确保模块105为了确保在读数据时,确保标识指针与当前读取位置处于环形队列中的不同位置,首先,设置一个大于等于1的读操作等待阈值,而读位置差值则是,在沿着环形队列的数据方向上与标识指针之间的位置差值;通俗的讲,就是当前读取位置与标识指针之间的间隔,而这个间隔是从当前读取位置到下一读取位置方向上所得的,请参考图4,图4示出了一种读位置差值的计算方式,或者说是表现方式。从图4中可以看出,读数据的方向和写数据的方向是一致的,当读数据的速度过快时,当前读取位置就可能达到或超过标识指针所在的位置。因此,设置一个读操作等待阈值,这个阈值至少为1,即当前读取位置与标识指针之间至少间隔一个位置,而具体的读操作等待阈值可以基于环形队列的长度、数据量的大小、读写的速度等等参数进行设置;当当前读取位置与标识指针所处的位置之间的差值小于或等于读操作等待阈值时,暂停读数据操作,即不再进行读数据操作;与此同时,实时监控读位置差值,在读位置差值大于读操作等待阈值时,重启读数据操作。

值得一提的是,在本实施例中,写操作和读操作之间,若偏重于写操作,即以写操作为主,那么,应该设置写操作等待阈值较小,若偏重于读操作,即以读操作为主,那么,应该设置读操作等待阈值较小。由于本实施例中的数组是定长数组,因此,在为了保证其中一个效果较好时设置更小的读/写操作等待阈值时,另一个写/读操作等待阈值就相应的设置为较大,具体如何权衡可以根据环形队列的长度、数据量的大小以及读写的速度来决定。

此外,由于本实施例中的基于环形队列的定长数组已经进行了编码,而读写操作一般都是根据编码的顺序而来,如写数据是从q[0]开始,经过q[1]、q[2]等等到q[7],然后再回到q[0]进入一个循环;而读数据亦如是,因此,若是用序号进行写位置差值和读位置差值的计算,那么沿着环形队列的数据方向,前者与后者之间的差值应该为负值,因此,本实施例中的写位置差值的准确表述应该是,标识指针所在位置沿环形队列的数据方向上与当前读取位置之间间隔的元素的数目,读位置差值的准确表述应该是,当前读取位置沿环形队列的数据方向上与标识指针所在位置之间间隔的元素的数目。

本实施例提供了一种内存管理装置,包括创建模块、设置模块、写数据模块、读数据模块以及确保模块,通过实施例的实施,实现了使用标识指针来进行数据的写入,且保证读写过程中标识指针和当前写入位置不重叠,满足和读写同步,节约了大量的系统资源。

第三实施例

请参考图5,图5为本发明第三实施例提供的一种内存管理方法流程图,包括:

S501、创建定长数组,并为定长数组的各元素分配分配存储空间,所述定长数组使用环形队列数据结构;

S502、设置一个基于环形队列的用于标识下一写入位置的标识指针;

S503、当写数据时,通过竞争获取标识指针,向标识指针对应的写入位置写入数据;使标识指针跳转到下一写入位置,释放标识指针;

S504、当读数据时,基于环形队列依次顺序读取数据,并更新当前读取位置;

其中,在写数据和读数据的过程中,确保标识指针与当前读取位置处于环形队列中的不同位置。

本实施例中的定长数组使用环形队列数据结构,环形队列是在实际编程中极为有用的数据结构,它有如下特点:

它是一个首尾相连的FIFO(First In First Out,先进先出)的数据结构,采用数组的线性空间,数据组织简单。能很快知道队列是否是满或是空。能以很快的速度来存取数据。

因为简单高效的原因,甚至在硬件上都实现了环形队列。

环形队列广泛应用于网络数据收发,和不同程序间数据交换(比如内核与应用程序大量交换数据,从硬件接收大量数据)均使用了环形队列。

实际上,内存并没有环形结构,因此环形队列实际上是数组的线性空间来实现。当数据到了尾部时,它将回到0位置处理。这个转回是通过取模操作来执行的。因此,环形队列逻辑上是将数组元素q[0]与q[n-1]连接,形成一个存放队列的环形空间。请参考图2,图2示出了一种具有八个元素的环形队列形态的定长数组,其中q[n-1]即为q[7]。

在实际使用中,环形队列并没有首尾之分,由于首尾相接,环形队列中所存储的数据也没有前后的区别;然而,环形队列的数据读写是有一定的方向的,虽然这个方向对于不同的环形队列而言是不一定的,但是对于某个特定的环形队列而言,这个方向是唯一确定的;用户所写入的数据是以这个确定的方向写入,用户读取数据也同样是以这个确定的方向进行读取。

定长数组的含义在于,数组的长度,或者说数组中允许存取元素的空间的数量是固定的;请继续参考图2,图2所示出的环形数组,其数组的长度是8,数组中允许存取元素的空间的数量也是8,以其中任意一个存取元素的空间作为起始元素q[0],以特定方向,图2中的为逆时针方向,各元素的编号分别为q[1]、q[2]、q[3]、q[4]、q[5]、q[6]、q[7];当定长数组的长度不是8,是更大或者更小的数时,与为8的情况类似;如不特殊说明,本实施例中所列举的定长数组的长度均是8。

其中,在本实施例中,关于定长数组的大小的选择方面有一定的要求,由于在环形队列中会用到取余操作,在大部分处理器上,取余操作并不高效,因此,在本实施例中,定长数组的元素的数量为2的指数倍,这样,计算余数只需要通过为操作index&(size-1)就能够得到实际的index。对外只有一个变量,那就是队尾元素的下标:cursor,这也避免了对head/tail这两个变量的操作和协同。

S502中,设置一个基于该环形队列的标识指针,用于标识下一写入位置。在本实施例中,在定长数组中写入数据是通过标识指针来指引的,即写入数据是在标识指针所在的位置写入;标识指针的逻辑是,在当前的位置写完数据后,会进行自增,即在环形队列的写数据方向上自行移动,然后,在标识指针所处的新的位置上继续写入数据。标识指针所占用的系统资源极少,且无需用户自行操作,它会自动在环形队列中移动。

S503中,当写数据时,通过竞争获取标识指针,向标识指针对应的写入位置写入数据。当不止一个数据要写入时,在同一个存储位置一般只存储一个对象写入的数据,那么,不同的对象之间就需要通过竞争,来获取标识指针,或者说获取标识指针的使用权,使该对象能够在标识指针所在的位置写入数据。

通过多线程分别执行CAS控制指令竞争获取标识指针。在实际写数据的过程中,在同一时间可能并不止有一个即将执行的写入操作,即进行写操作的对象并不止一个;如果两个或以上的对象同时都想写入数据,则他们会同时执行CAS指令,具体为CAS(slot,slot+1),然后执行成功的竞争成功,获取标识指针,或者说是获取标识指针对应的写入位置的存储权,获取该存储权的对象就可以将数据写入,其他的未获取成功的则需要继续下一个CAS指令申请之后的标识指针。在这一过程中,一般并不需要用到锁,使用的是系统的CAS指令。

在很多时候会有多个对象去抢数组上的同一个位置,在一般的java程序中,是通过加锁来实现,但本实施例是通过CAS来实现的,多个会去竞争,但不会存在两个同时抢到,抢不到的就抢下一个位置。读写双方都要检查对方的位置,防止超过对方。在本实施例中,检查的策略可以包括主动检查,比如按照一定的时间间隔周期性的检查对方的位置,或者等待对方的通知,如设置一道指令,令对方读/写到环形队列的某一位置即发送通知。

在当前位置的数据写完之后,标识指针跳转到下一写入位置,释放标识指针。其中,释放标识指针,或者说释放标识指针的控制权,在前一次的数据写入完成后,释放的标识指针会自动的沿着数据写入的方向跳转到下一写入位置,等待下一数据的写入。

S504中,当读数据时,基于环形队列依次顺序读取数据,并更新当前读取位置。基于环形队列依次顺序读取数据,指的就是在环形队列中,数据的读取是按照一个特定的方向来的,对于一个特定的环形队列而言,这个方向是确定的,与写数据的方向一致。

在写数据和读数据的过程中,确定标识指针和当前读取位置处于环形队列中的不同位置。由于在数据读写的过程中,有着写满不写,读空不读的要求,即环形队列中即将在下一个位置写数据时,该下一个位置的数据仍然未被读取,那么就不应再写;以及在环形队列中,即将读取下一位置的数据时,下一位置的数据为空或者尚未写完,那么就不应再读。如果在下一位置的数据仍未被读取时写入数据的话,那么就会导致数据丢失;如果在下一位置的数据为空或者尚未写完时读取数据的话,就会读取到空的数据,浪费系统资源和时间。

而正常而言,数据读写的过程中,一个数据总是先被写入之后,再被读取,换言之,对于一个数据而言,写入在先,读取在后,在环形队列中,总是先写的数据先被读取,那么,在满足写满不写,读空不读时,标识指针和当前读取位置总是处于环形队列中的不同位置的。

本实施例中,为了确保标识指针和当前读取位置总是处于环形队列中的不同位置,还可以包括:

设置一个大于等于1的写操作等待阈值;

在写数据时,当写位置差值小于等于写操作等待阈值时,暂停写数据操作,其中,写位置差值为标识指针沿着环形队列的数据方向上与当前读取位置之间的位置差值;

监控写位置差值,并在写位置差值大于写操作等待阈值时重启写数据操作。

也就是说,首先,设置一个大于等于1的写操作等待阈值,而写位置差值则是标识指针,在沿着环形队列的数据方向上与当前读取位置之间的位置差值;通俗的讲,就是标识指针与当前读取位置之间的间隔,而这个间隔是从标识指针到下一写入位置方向上所得的,请参考图3,图3示出了一种写位置差值的计算方式,或者说是表现方式。从图3中可以看出,读数据的方向和写数据的方向是一致的,当写数据的速度过快时,标识指针的位置就可能达到或者超过当前读取位置。因此,设置一个写操作等待阈值,这个阈值至少为1,即标识指针与当前读取位置之间至少间隔一个位置,而具体的写操作等待阈值可以基于环形队列的长度、数据量的大小、读写的速度等等参数进行设置;当标识指针所处的位置与当前读取位置之间的差值小于或等于写操作等待阈值时,暂停写数据操作,即不再进行写数据操作;与此同时,实时监控写位置差值,在写位置差值大于写操作等待阈值时,重启写数据操作。

本实施例中,为了确保标识指针和当前读取位置总是处于环形队列中的不同位置,还可以包括:

设置一个大于等于1的读操作等待阈值;

在读数据时,当读位置差值小于等于读操作等待阈值时,暂停读数据操作,其中,读位置差值为当前读取位置沿着环形队列的数据方向上与标识指针之间的位置差值;

监控读位置差值,并在读位置差值大于读操作等待阈值时重启读数据操作。

也就是说,首先,设置一个大于等于1的读操作等待阈值,而读位置差值则是,在沿着环形队列的数据方向上与标识指针之间的位置差值;通俗的讲,就是当前读取位置与标识指针之间的间隔,而这个间隔是从当前读取位置到下一读取位置方向上所得的,请参考图4,图4示出了一种读位置差值的计算方式,或者说是表现方式。从图4中可以看出,读数据的方向和写数据的方向是一致的,当读数据的速度过快时,当前读取位置就可能达到或超过标识指针所在的位置。因此,设置一个读操作等待阈值,这个阈值至少为1,即当前读取位置与标识指针之间至少间隔一个位置,而具体的读操作等待阈值可以基于环形队列的长度、数据量的大小、读写的速度等等参数进行设置;当当前读取位置与标识指针所处的位置之间的差值小于或等于读操作等待阈值时,暂停读数据操作,即不再进行读数据操作;与此同时,实时监控读位置差值,在读位置差值大于读操作等待阈值时,重启读数据操作。

值得一提的是,在本实施例中,写操作和读操作之间,若偏重于写操作,即以写操作为主,那么,应该设置写操作等待阈值较小,若偏重于读操作,即以读操作为主,那么,应该设置读操作等待阈值较小。由于本实施例中的数组是定长数组,因此,在为了保证其中一个效果较好时设置更小的读/写操作等待阈值时,另一个写/读操作等待阈值就相应的设置为较大,具体如何权衡可以根据环形队列的长度、数据量的大小以及读写的速度来决定。

本实施例提供了一种内存管理方法,创建定长数组,为定长数组的各元素分配存储空间,定长数组使用环形队列数据结构,设置一个基于环形队列的用于标识下一写入位置的标识指针;当写数据时,通过竞争获取标识指针,像标识指针对应的写入位置写入数据,读数据时,基于环形队列依次顺序读取数据,在读写的过程中,确保标识指针和当前读取位置处于环形队列中的不同位置。通过本发明的实施,使用标识指针来进行数据的写入,且保证读写过程中标识指针和当前写入位置不重叠,从而满足了读写同步,节约了大量的系统资源。

第四实施例

请参考图6,图6为本发明第四实施例提供的一种内存管理方法流程图。

本实施例以生产者和消费者为例,对数据的读写做进一步说明,其中生产者一般作为写入数据的对象,而消费者则作为读取数据的对象。

S601、创建定长数组,为定长数组的个元素分配存储空间,定长数组使用环形队列数据结构;

S602、设置一个基于环形队列的用于标识下一写入位置的标识指针;

S603、生产者通过竞争获取标识指针,向标识指针对应的写入位置写入数据;

S604、消费者基于环形队列依次顺序读取数据,更新当前读取位置。

其中,生产者和消费者读写数据的过程中,确保标识指针和当前读取位置处于环形队列中的不同位置。

在实际使用中,环形队列并没有首尾之分,由于首尾相接,环形队列中所存储的数据也没有前后的区别;然而,环形队列的数据读写是有一定的方向的,虽然这个方向对于不同的环形队列而言是不一定的,但是对于某个特定的环形队列而言,这个方向是唯一确定的;生产者所写入的数据是以这个确定的方向写入,消费者读取数据也同样是以这个确定的方向进行读取。

关于定长数组的大小的选择方面有一定的要求,由于在环形队列中会用到取余操作,在大部分处理器上,取余操作并不高效,因此,在本实施例中,定长数组的元素的数量为2的指数倍,这样,计算余数只需要通过为操作index&(size-1)就能够得到实际的index。对外只有一个变量,那就是队尾元素的下标:cursor,这也避免了对head/tail这两个变量的操作和协同。

设置一个基于该环形队列的标识指针,用于标识下一写入位置。在本实施例中,在定长数组中写入数据是通过标识指针来指引的,即写入数据是在标识指针所在的位置写入;标识指针的逻辑是,在当前的位置写完数据后,会进行自增,即在环形队列的写数据方向上自行移动,然后,在标识指针所处的新的位置上继续写入数据。标识指针所占用的系统资源极少,且无需用户自行操作,它会自动在环形队列中移动。

通过多线程分别执行CAS控制指令竞争获取标识指针。在实际写数据的过程中,在同一时间可能并不止有一个即将执行的写入操作,即进行写操作的生产者并不止一个;如果两个或以上的生产者同时都想写入数据,则他们会同时执行CAS指令,具体为CAS(slot,slot+1),然后执行成功的竞争成功,获取标识指针,或者说是获取标识指针对应的写入位置的存储权,获取该存储权的对象就可以将数据写入,其他的未获取成功的生产者则需要继续下一个CAS指令申请之后的标识指针。在这一过程中,一般并不需要用到锁,使用的是系统的CAS指令。

在很多时候会有多个生产者去抢数组上的同一个位置,在一般的java程序中,是通过加锁来实现,但本实施例是通过CAS来实现的,多个会去竞争,但不会存在两个同时抢到的情况,抢不到的就抢下一个位置。

消费者基于环形队列依次顺序读取数据,指的就是在环形队列中,数据的读取是按照一个特定的方向来的,对于一个特定的环形队列而言,这个方向是确定的,与写数据的方向一致。

为了防止生产者生产过快,在环形队列中覆盖消费者的数据,生成者要对消费者的消费情况进行跟踪,即读取各消费者当前的读取位置。

消费者需要等待有新元素进入方能继续读取,也就是说标识指针大于当前读取位置。等待策略有多种,可以选择sleep wait可以根据场景选择不同的等待策略。

生产者和消费者双方都要检查对方的位置,防止超过对方。在本实施例中,检查的策略可以包括主动检查,比如按照一定的时间间隔周期性的检查对方的位置,或者等待对方的通知,如设置一道指令,令对方读/写到环形队列的某一位置即发送通知。比如,消费者可以说“当你的位置比X大的时候请告诉我”,说明X之前的节点已经被生产者写入了数据,而且消费者对这些节点的操作是读而不是写,因此访问不用加锁。

需要说明的是,在本文中,术语“包括”、“包含”或者其任何其他变体意在涵盖非排他性的包含,从而使得包括一系列要素的过程、方法、物品或者装置不仅包括那些要素,而且还包括没有明确列出的其他要素,或者是还包括为这种过程、方法、物品或者装置所固有的要素。在没有更多限制的情况下,由语句“包括一个……”限定的要素,并不排除在包括该要素的过程、方法、物品或者装置中还存在另外的相同要素。

上述本发明实施例序号仅仅为了描述,不代表实施例的优劣。

通过以上的实施方式的描述,本领域的技术人员可以清楚地了解到上述实施例方法可借助软件加必需的通用硬件平台的方式来实现,当然也可以通过硬件,但很多情况下前者是更佳的实施方式。基于这样的理解,本发明的技术方案本质上或者说对现有技术做出贡献的部分可以以软件产品的形式体现出来,该计算机软件产品存储在一个存储介质(如ROM/RAM、磁碟、光盘)中,包括若干指令用以使得一台终端设备(可以是手机,计算机,服务器,空调器,或者网络设备等)执行本发明各个实施例所述的方法。

上面结合附图对本发明的实施例进行了描述,但是本发明并不局限于上述的具体实施方式,上述的具体实施方式仅仅是示意性的,而不是限制性的,本领域的普通技术人员在本发明的启示下,在不脱离本发明宗旨和权利要求所保护的范围情况下,还可做出很多形式,这些均属于本发明的保护之内。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1