三九宝宝网宝宝教育学龄段教育

数据缓冲区的解决数据缓冲区内存的方案

02月10日 编辑 39baobao.com

[可以不用缓冲溶液培养细胞么]在细胞培养时,细胞的呼吸作用会产生很多CO2,和水结合会使细胞的生长环境PH下降,(酸化),这样不利于细胞的培养,为了保证细胞的培养环境在一个合理的酸碱平衡环境,就需要在培养液中加...+阅读

从概念上讲,数据缓冲区在传统方案下是由两个操作创建的:数据缓冲区实体的创建和实际内存的分配。然而事实上,在实际数据变得可用之前,您不需要分配实际的内存 —— 即可以将两个操作分离开来。最初可以使用内存块的一个空链表来创建一个抽象缓冲区。抽象数据缓冲区仅在实际数据变得可用时才分配内存。释放内存也变成了抽象数据缓冲的责任。

考虑到所有这些,集中内存管理和数据复制操作就会带来以下优点:各方都能通过调用预定义的 API 函数来构造和/或销毁数据缓冲区。 内存使用将保持接近最优状态,因为缓冲区内存仅在必要时才分配,并且会尽快释放,从而最小化内存泄露。 任何一方都不需要知道底层的内存管理方案,使得软件高度可移植,同时保证了交互双方之间的兼容性。

由于没有哪一方需要管理内存,确定缓冲区的大小就变得不必要了(因而也不可能存在前面指出的多次执行问题)。 事实证明缓冲区溢出也不可能会发生,因为仅当存在额外数据空间时才会复制数据。一种简单的实现为了表示一个抽象数据缓冲区,需要声明两个结构化的数据类型:清单 1. 声明两个结构化的数据类型来表示一个抽象数据缓冲区 typedef struct BufferBlockHeader_st BufferBlockHeader; struct BufferBlockHeader_st { BufferBlockHeader * pNextBlock;}; struct Buffer_st { long int totalLength; BufferBlockHeader * pFirstBlock; short int startPoint; BufferBlockHeader * pLastBlock; short int endPoint;}; typedef struct Buffer_st Buffer; Buffer 包含关于已创建的抽象缓冲区的信息,它还管理内存块的一个链表:totalLoength 记录当前存储在缓冲区中的字节数。

pFirstBlock 指向该链表中的第一个内存块。 startPoint 记录第一个内存块中第一个字节的偏移位置。 pLostBlock 指向该链表的最后一个内存块。 endPoint 记录最后一个内存块中第一个空闲字节的偏移位置。您可以向 Buffer 引入一个附加参数,用以指定每个内存块的大小,并且可以在抽象缓冲区的初始化期间,将该参数设置为一个可取的值。这里假设使用默认块大小。

如果分配了的话, BufferBlockHeader 结构中的 pNextBlock 总是指向该链表中的下一个内存块。每个内存块在分配时都包含一个 BufferBlockHeader 头,后面跟着一个用于存储实际数据的缓冲区块。图 1 描述了一个存储了一些数据的抽象缓冲区。图 1. 抽象缓冲区的数据结构M 表示 Buffer 的大小(它通常为 20 字节), B 表示所选择的内存块大小。内存开销大约为 (M+B) 个字节(每个内存块开头的指针忽略不计)。

(M+B) 中的 B 平均起来仅有所使用的第一和最后一个内存块的一半。这个开销几乎保持不变。在能够缓冲数据之前,必须通过调用下面的 newBuffer() 函数来显式地创建抽象缓冲区:清单 2 使用 newBuffer() 函数创建抽象缓冲区 Buffer * newBuffer() { allocate a Buffer structure; initialize the structure;} 在 清单 2中,该函数分配了包含一个 Buffer 的内存块,并初始化它的条目以指明它是一个空抽象缓冲区。

相应地,必须在使用抽象缓冲区之后通过调用下面的 freeBuffer() 函数来销毁它:清单 3 使用 freeBuffer() 函数来销毁抽象缓冲区 void freeBuffer(Buffer * pBuffer /* pointer to the buffer to be freed */ ) { while (there is more memory block in the linked list) { free the next memory block; } free the Buffer structure;} 清单 3中的函数释放链表中的所有内存块,然后释放由 newBuffer() 分配的 Buffer 。

要逐步向抽象缓冲区追加数据段,可使用以下函数:清单 4. 逐步向抽象缓冲区追加数据段 long int appendData(Buffer * pBuffer, /* pointer to the abstract buffer */ byte * pInput, /* pointer to the data source */ long int offset, /* offset of the input data */ long int dataLength /* number of bytes of the input data */ ) { while (there is more input data) { fill the current memory block; if (there is more input data) { allocate a new memory block and add it into the linked list; } } } 清单 4中的函数把存储在 pInput[offset..offset+dataLength] 中的字节复制到 pBuffer 所指向的抽象缓冲区中,并在必要时在链表中插入新的内存块,然后返回成功复制到抽象缓冲区中的字节数目。

采用类似的方式,您可以使用以下函数,逐段地从抽象缓冲区读取数据段:清单 5. 从抽象缓冲区读取数据段 long int readData(Buffer * pBuffer, /* pointer to the abstract buffer */ byte * pOutput, /* pointer to the output byte array */ long int offset, /* offset of the output byte array */ long int arrayLength /* size of available output byte array */ ) { while (there is something more to read and there is room for output) { read from the first memory block; if (the first memory block is empty) { delete the first memory block from the linked list and free its memory; } }} 在 清单 5 中,该函数销毁性地从 pBuffer 所指向的抽象缓冲区最多读取 arrayLength 个前导字节,并在内存块变为空时从链表中删除它们,然后返回成功读取的字节数目。

如果需要,您可以实现一个类似 readData() 的函数来允许非销毁性的读取。实现一个函数来返回当前存储在抽象缓冲区中...

以下为关联文档:

数据解决方案有哪些应用难点需要在更短的时间内处理更多的数据。 你可曾知道,每天生成的数据多达2.5 x 1018字节?你能说出贵企业的所有数据源吗?面对众多的传感器、社交媒体、事务记录、手机及更多数据源,...

推荐阅读
图文推荐