是否有允许动态增长和扩展 java.nio.ByteBuffer 的 ByteBuffer 实现?

Is there an implementation of ByteBuffer that allows for dynamic growing and extends java.nio.ByteBuffer?

我的代码中有一个 java.nio.ByteBuffer:

ByteBuffer bb = ByteBuffer.allocateDirect(1024);
... 

我希望能够将它替换为新的 ByteBuffer 实现(即它必须扩展 java.nio.ByteBuffer),以便重新分配、复制和丢弃之前的小 ByteBuffer -hood,允许无缝动态增长。

我不能只有一个包装器,因为它必须是一个 java.nio.ByteBuffer

它必须是这样的:

ByteBuffer bb = new MyImplementationOfByteBufferThatExtendsByteBuffer(1024);

有人见过或做过吗?可能吗?

只是想指出,如果 java.nio.ByteBuffer 是一个接口而不是一个抽象 class,那将很容易实现。俗话说,如果你想要灵活性,classes 更喜欢接口而不是抽象。

不,这个不存在,并且不能存在而不违反ByteBuffer的superclassBuffer:

A buffer is a linear, finite sequence of elements of a specific primitive type. Aside from its content, the essential properties of a buffer are its capacity, limit, and position:

  • A buffer's capacity is the number of elements it contains. The capacity of a buffer is never negative and never changes.

因此,如果允许“无缝动态增长”,ByteBuffer 将不再充当缓冲区。无论 接口还是抽象 classes,这也是正确的:subclasses 和接口实现都不应破坏在 classes 中定义的不变量延长。毕竟,您的 HypotheticalGrowingByteBuffer 的消费者可能依赖 Buffer 的固定容量来缓存对 capacity() 的单个调用,否则将被定义为不更改。

使 ByteBuffer 成为抽象 class 而不是接口的另一个激励因素:支持缓冲区的内存被定义为必须固定且连续,这比更灵活的定义具有更高的性能。

也就是说,Buffer 定义了一个可变的概念 limit,其中一个大的 originally-allocated 缓冲区可能会人为地限制其可用性。您可以使用它来限制大缓冲区从小开始然后增长,尽管增长不会是“无缝的”;它将受到您定义的原始缓冲区容量的限制。如果目标只是连接较小的 fixed-size 缓冲区,其中总大小是可预测的,则可能值得使用 ByteBuffer.duplicate 并设置 标记将它们生成为较大缓冲区的片段limit限制可写区域。

我很确定 ByteBuffers 具有固定容量是故意的。我鼓励您不要试图解决它,就好像它是一个设计缺陷一样。接受它并将其视为有目的的限制。

如果您允许 ByteBuffers 增长,那么 compact() 将不再具有可预测的最大运行时间。缓冲区越大,压缩它所需的时间就越长。我在我的 NIO-based 套接字库中遇到了这个问题。我有内部缓冲区增长以容纳大量数据注入,结果是性能下降与缓冲的数据量成正比。

例如,有人可能会尝试一次发送 100MB 的数据,所以我会将该数据保存在一个 100MB 的 ByteBuffer 中。处理代码一次只能处理大约 32KB,因此它会从缓冲区中提取 32KB 的数据,然后对其进行压缩。然后是另一个 32KB 和另一个压缩。它会继续读取和压缩,直到缓冲区被耗尽。

每个压缩都是一个 O(n) 操作,我执行了 O(n) 多个操作,导致整体运行时间为 O(n2)。真是个坏消息。当缓冲区变得如此之大以至于 I/O 请求开始超时时,我注意到了这个问题,因为 I/O 线程一直在压缩 ByteBuffers。

解决方法:如果你想要动态缓冲区,创建一个Queue<ByteBuffer>。队列可以增长并容纳无限数量的 ByteBuffer,而每个缓冲区保持固定大小。这将使您的应用程序正确扩展而不会遇到 O(n2) 问题。