【发布时间】:2010-12-18 23:32:08
【问题描述】:
有没有人见过 java.nio.ByteBuffer 的实现,如果 putX() 调用超出容量,它会动态增长?
我想这样做的原因有两个:
- 我不知道我提前需要多少空间。
- 我宁愿在每次空间用完时都执行新的 ByteBuffer.allocate(),然后执行批量 put()。
【问题讨论】:
标签: java bytebuffer
有没有人见过 java.nio.ByteBuffer 的实现,如果 putX() 调用超出容量,它会动态增长?
我想这样做的原因有两个:
【问题讨论】:
标签: java bytebuffer
为了使异步 I/O 工作,您必须拥有连续的内存。在 C 中,您可以尝试重新分配数组,但在 Java 中,您必须分配新内存。您可以写信给ByteArrayOutputStream,然后在准备发送时将其转换为ByteBuffer。缺点是你在复制内存,而高效 IO 的关键之一是减少内存复制的次数。
【讨论】:
ArrayList 与数组的权衡相同。就像ArrayList 一样,您可以使用初始容量(构造函数ByteArrayOutputStream(int capacity))对其进行实例化。例如如果您期望大约 800 字节的数据,请使用 new ByteArrayOutputStream(1024) 之类的内容。这将防止(或减少)调整大小。
看看 Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html 这是一个替代品(它包装了 ByteBuffer)
不过,我建议你分配的比你需要的多,不要太担心。如果您分配一个缓冲区(尤其是直接缓冲区),操作系统会为其提供虚拟内存,但它仅在实际使用时才使用物理内存。虚拟内存应该很便宜。
【讨论】:
ByteBuffer 不能真正以这种方式工作,因为它的设计理念是只是一个特定数组的 view,您也可以直接引用它。它无法尝试将该数组换成更大的数组而不会发生奇怪的事情。
您要使用的是DataOutput。最方便的方法是使用(预发布)Guava 库:
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();
但您也可以手动从 ByteArrayOutputStream 创建 DataOutputStream,并通过将虚假 IOException 链接到 AssertionErrors 中来处理它们。
【讨论】:
ByteArrayDataOutput 也没有出现 ByteStreams。你指的是什么?
new DataOutputStream(new ByteArrayOutputStream()) 会更容易。
DataOutput,然后举了两个例子。一个使用番石榴,另一个正是您在评论中所说的。 ByteArrayDataOutput 和 DataOutputStream 都实现了该接口。
看看 Netty 的 DynamicChannelBuffer 可能也值得一看。我觉得方便的是:
slice(int index, int length)
【讨论】:
另一种选择是使用带有大缓冲区的直接内存。这会消耗虚拟内存,但只使用与您使用的一样多的物理内存(按页面,通常为 4K)
因此,如果您分配 1 MB 的缓冲区,它会消耗 1 MB 的虚拟内存,但唯一的操作系统会为实际使用的应用程序提供物理页面。
效果是您会看到您的应用程序使用大量虚拟内存但相对较少的常驻内存。
【讨论】:
向量允许持续增长
Vector<Byte> bFOO = new Vector<Byte>();bFOO.add((byte) 0x00);`
【讨论】:
要序列化某些东西,您需要在条目中输入对象。您可以做的是将您的对象放入对象集合中,然后进行循环以获取迭代器并将它们放入字节数组中。然后,拨打ByteBuffer.allocate(byte[].length)。这就是我所做的,它对我有用。
【讨论】:
确实,使用自动扩展缓冲区更加直观。如果你能负担得起重新分配的性能奢侈,你为什么不呢!?
Netty 的ByteBuf 正是为您提供了这一点。就好像他们把java.nio 的ByteBuffer 刮掉了边缘,让它更容易使用。
此外,它是 on Maven in an independent netty-buffer 包,因此您无需包含完整的 Netty 套件即可使用。
【讨论】:
我建议使用输入流从文件接收数据(如果您需要非阻塞,则使用单独的线程),然后将字节读入 ByteArrayOutstream,这样您就可以将其作为字节数组获取。这是一个简单的示例,无需添加太多解决方法。
try (InputStream inputStream = Files.newInputStream(
Paths.get("filepath"), StandardOpenOption.READ)){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int byteRead = 0;
while(byteRead != -1){
byteRead = inputStream.read();
baos.write(byteRead);
}
ByteBuffer byteBuffer = ByteBuffer.allocate(baos.size())
byteBuffer.put(baos.toByteArray());
//. . . . use the buffer however you want
}catch(InvalidPathException pathException){
System.out.println("Path exception: " + pathException);
}
catch (IOException exception){
System.out.println("I/O exception: " + exception);
}
【讨论】:
另一种解决方案是分配足够多的内存,填充ByteBuffer,然后只返回占用的字节数组:
初始化一个大ByteBuffer:
ByteBuffer byteBuffer = ByteBuffer.allocate(1000);
在你把东西放进去之后:
private static byte[] getOccupiedArray(ByteBuffer byteBuffer)
{
int position = byteBuffer.position();
return Arrays.copyOfRange(byteBuffer.array(), 0, position);
}
但是,从一开始就使用org.apache.commons.io.output.ByteArrayOutputStream 可能是最好的解决方案。
【讨论】:
Netty ByteBuf 在这方面做得很好。
【讨论】: