我的代码中有一个java.nio.ByteBuffer:
ByteBuffer bb = ByteBuffer.allocateDirect(1024);
...
我希望能够将其替换为ByteBuffer的新实现(即,它必须扩展java.nio.ByteBuffer),以便它可以在后台重新分配,复制和丢弃以前的小ByteBuffer。 ,以实现无缝的动态增长。
我不能只拥有一个包装,因为它必须是java.nio.ByteBuffer
。
那一定是这样的:
ByteBuffer bb = new MyImplementationOfByteBufferThatExtendsByteBuffer(1024);
有人见过或做过吗?有可能吗?
仅需注意,如果java.nio.ByteBuffer
是接口而不是抽象类,则实现起来很简单。就像俗话说的那样,如果想要灵活性,偏爱抽象类上的接口。
答案 0 :(得分:1)
不,这不存在,并且 不存在而不违反ByteBuffer的超类Buffer的约定:
缓冲区是特定原始类型的元素的线性有限序列。除了其内容之外,缓冲区的基本属性还包括其容量,限制和位置:
- 缓冲区的容量是它包含的元素数量。缓冲区的容量永远不会为负,也不会改变。
因此,如果允许“无缝动态增长”,则ByteBuffer将不再充当Buffer。不管接口还是抽象类,这都是正确的:子类和接口实现都不应破坏在其扩展的类中定义的不变式。毕竟,您的HypotheticalGrowingByteBuffer的使用者可能依赖Buffer的固定容量来缓存对capacity()
的单个调用,否则将被定义为不更改。
使ByteBuffer成为抽象类而非接口的另一个诱因:支持缓冲区的内存必须固定且连续,这比更灵活的定义可以提供更高的性能。
也就是说,Buffer定义了limit
的可变概念,在该概念中,最初分配的较大缓冲区可能会受到人为限制。您可以使用它来约束较大的缓冲区,从较小的缓冲区开始,然后进行增长,尽管增长并不是“无缝”的。它会受到您定义的原始缓冲区容量的限制。如果目标只是连接整体大小可预测的较小固定大小的缓冲区,则可能值得使用ByteBuffer.duplicate并设置 mark 将它们生成为较大缓冲区的片段和 limit 来限制可写区域。
答案 1 :(得分:0)
我很确定ByteBuffer具有固定的容量是有意的。我鼓励您不要尝试解决它,好像它是设计缺陷一样。接受并接受它作为有目的的限制。
如果允许ByteBuffers增长,那么compact()
将不再具有可预测的最大运行时间。缓冲区越大,压缩它所需的时间就越长。我在基于NIO的套接字库中恰好遇到了这个问题。我的内部缓冲区不断增长,无法容纳大量数据,结果导致性能下降与缓冲的数据量成正比。
例如,某人可能尝试一次发送100MB数据,因此我会将这些数据保存在单个100MB ByteBuffer中。处理代码一次只能处理大约32KB,因此它将从缓冲区中提取32KB数据,然后对其进行压缩。然后是另一个32KB和另一个压缩。它会继续读取并压缩,直到耗尽缓冲区。
每个压缩都是O(n)操作,而我在其中执行了O(n)多次,导致总体运行时间为O(n 2 )。真是个坏消息。当缓冲区过大以至于I / O请求开始超时时,我注意到了这个问题,因为I / O线程花了所有时间压缩ByteBuffer。
解决方案::如果要使用动态缓冲区,请创建一个Queue<ByteBuffer>
。当每个缓冲区保持固定大小时,队列可以增长并容纳无限数量的ByteBuffer。这将使您的应用程序正确扩展,而不会遇到O(n 2 )问题。