簡體   English   中英

不斷增長的 ByteBuffer

[英]Growing ByteBuffer

有沒有人見過 java.nio.ByteBuffer 的實現,如果 putX() 調用超出容量,它會動態增長?

我想這樣做的原因有兩個:

  1. 我不知道我需要提前多少空間。
  2. 我寧願不做一個新的 ByteBuffer.allocate() 然后每次用完空間時都做一個批量 put()。

為了讓異步 I/O 工作,你必須有連續的內存。 在 C 中你可以嘗試重新分配一個數組,但在 Java 中你必須分配新的內存。 您可以寫入ByteArrayOutputStream ,然后在准備發送時將其轉換為ByteBuffer 缺點是您正在復制內存,而高效 IO 的關鍵之一是減少復制內存的次數。

ByteBuffer 不能真正以這種方式工作,因為它的設計概念只是一個特定數組的視圖,您也可以直接引用它。 它無法嘗試將該數組交換為更大的數組而不會發生奇怪的事情。

您要使用的是DataOutput 最方便的方法是使用(預發布)Guava 庫:

ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();

但是您也可以手動從 ByteArrayOutputStream 創建一個 DataOutputStream,並通過將它們鏈接到 AssertionErrors 來處理虛假的 IOExceptions。

看看 Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html這是一個替代品(它包裝了 ByteBuffer)

但是,我建議你分配比你需要的更多,不要太擔心。 如果您分配一個緩沖區(尤其是直接緩沖區),操作系統會為其提供虛擬內存,但僅在實際使用時才使用物理內存。 虛擬內存應該很便宜。

看看 Netty 的DynamicChannelBuffer也可能是值得的。 我覺得方便的事情是:

  • slice(int index, int length)
  • 無符號操作
  • 分離的作者和讀者索引

另一種選擇是使用帶有大緩沖區的直接內存。 這會消耗虛擬內存,但僅使用您使用的物理內存(按頁面,通常為 4K)

因此,如果您分配 1 MB 的緩沖區,它會占用 1 MB 的虛擬內存,但唯一的操作系統為實際使用的應用程序提供物理頁面。

結果是您看到您的應用程序使用了大量虛擬內存,但駐留內存量相對較少。

事實上,自動擴展緩沖區使用起來更加直觀。 如果你能負擔得起重新分配的性能奢侈,你為什么不呢!?

Netty 的ByteBuf正是為您提供了這一點。 就像他們采用了java.nioByteBuffer並刮掉了邊緣,使其更易於使用。

此外,它位於 Maven 上的獨立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 在這方面做得很好。

Vector 允許持續增長

Vector<Byte> bFOO = new Vector<Byte>(); bFOO.add((byte) 0x00);`

要序列化某些東西,您將需要條目中的對象。 您可以做的是將您的對象放在對象集合中,然后進行循環以獲取迭代器並將它們放入字節數組中。 然后,調用ByteBuffer.allocate(byte[].length) 這就是我所做的,它對我有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM