2009-11-21 6 views
32

Кто-нибудь видел реализацию java.nio.ByteBuffer, которая будет динамически расти, если вызов putX() переполняет емкость?Growing ByteBuffer

Поэтому я хочу, чтобы сделать это таким образом двояко:

  1. Я не знаю, сколько места мне нужно больше времени.
  2. Я бы предпочел не использовать новый ByteBuffer.allocate(), а затем массив put() каждый раз, когда у меня заканчивается пробел.

ответ

25

Для работы асинхронного ввода-вывода у вас должна быть непрерывная память. В C вы можете попытаться перераспределить массив, но в Java вы должны выделить новую память. Вы можете написать ByteArrayOutputStream, а затем конвертировать его в ByteBuffer в то время, когда вы будете готовы отправить его. Недостатком является то, что вы копируете память, и один из ключей к эффективному IO уменьшает количество копий памяти.

+1

ByteArrayOutputStream на самом деле именно то, что я хочу (я вообще не делаю никаких операций ввода-вывода, у меня просто есть сложная сериализация). Благодаря! – Seth

+1

Сет, ваше утверждение вопроса («putX») подразумевает, что вам понадобятся такие методы, как putInt, putDouble и т. Д., Что подразумевает, что ByteArrayOutputStream будет недостаточно для вас, поэтому мой ответ ByteArrayDataOutput. –

+0

Я даже не спрошу, как фиксированный размер buf именно то, что вы хотите после того, как попросите неограниченный размер buf. Мы живем в мире, где абсурд - это норма. – Val

6

Посмотрите Mina IOBuffer https://mina.apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html, который является падение замены (она оборачивает ByteBuffer)

Однако я предлагаю вам выделить больше, чем нужно, и не беспокоиться об этом слишком много. Если вы выделяете буфер (esp прямой буфер), OS дает ему виртуальную память, но при использовании фактически использует только физическую память. Виртуальная память должна быть очень дешевой.

+6

Мне нравится предупреждение на странице: «Основная причина, почему MINA имеет свою собственную оболочку поверх nio ByteBuffer, имеет расширяемые буферы. Это было очень плохое решение». – Suppressingfire

+0

Действительно, запись в память подразумевает, что вы в конечном итоге хотите какой-то предел и, более того, не тот большой предел. Еще любопытно узнать, остается ли неиспользованная часть ArrayBuffer бесплатной для других приложений/применений или нет. – Val

+1

Ссылка мертва. 404. – luckydonald

8

ByteBuffer не может работать так, поскольку его концепция дизайна должна быть просто вид определенного массива, к которому вы также можете обратиться напрямую. Он не мог попытаться поменять этот массив для большего массива без каких-либо странностей.

Что вы хотите использовать, это DataOutput. Наиболее удобный способ заключается в использовании (пре-релиз) библиотеки Guava:

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

Но вы также можете создать DataOutputStream из ByteArrayOutputStream вручную, а просто иметь дело с подложным IOExceptions, приковав их в AssertionErrors.

+0

Ни 'ByteArrayDataOutput', ни' ByteStreams' не отображаются в JDK, начиная с Java 8. Что вы имеете в виду? – EJP

+0

@EJP Это классы из [Google Guava] (https://code.google.com/p/guava-libraries/), о которых упоминал Кевин. – Jesper

+0

@ Jesper Я не нахожу его заявление совершенно ясным. Сначала он утверждает, что * такой класс, а затем он утверждает, что «наиболее удобным способом является использование (до выпуска) библиотеки Guava». Если такой класс не предоставлен другой библиотекой, это способ * только * использовать его. Было бы легче избежать сторонних библиотек вообще и просто использовать 'new DataOutputStream (новый ByteArrayOutputStream())'. – EJP

4

Возможно, стоит взглянуть на номер DynamicChannelBuffer компании Netty. Вещи, которые я нахожу под рукой, являются:

  • slice(int index, int length)
  • неподписанные операции
  • отделенные писатель и читатель индексирует
4

Другой вариант заключается в использовании прямой памяти с большим буфером. Это потребляет виртуальную память, но использует только столько физической памяти, сколько вы используете (на странице, которая обычно равна 4K).

Итак, если вы выделяете буфер объемом 1 МБ, то он составляет 1 МБ виртуальной памяти, но единственная ОС дает физическую страниц к используемому приложению.

Эффект: вы видите свое приложение, используя много виртуальной памяти, но относительно небольшое количество резидентной памяти.

+0

, пожалуйста, добавьте пример кода – Alex

-2

Вектор позволяет для непрерывного роста

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

+5

С помощью этого метода для каждого байта вам необходимо создать объект Byte, который будет содержать 8-байтовый заголовок, +1 байт, чтобы сохранить значение внутри объекта. Теперь все объекты java занимают несколько 8 байтов, что составляет 16 байт на объект. Допустим, мы используем 32-битную систему, поэтому ссылки на эти объекты в векторе составляют по 4 байта. Поэтому для хранения каждого байта вам нужно 20 байт памяти. Это просто не очень хорошо. – Numeron

+0

@Numeron Byte - мухи, в JVM имеется ровно 256 экземпляров, если вы не называете «new» вместо «valueOf». Авто-бокс делает последнее. Но ответ низок, так как бокс-косвенность будет значительно больше и медленнее, даже если нет выделенных байт-объектов. –

-6

Чтобы сериализовать что-то, вам понадобится объект во вход. Что вы можете сделать, это поместить ваш объект в коллекцию объектов, а после этого сделать цикл для получения итератора и поместить их в массив байтов. Затем позвоните по номеру ByteBuffer.allocate(byte[].length). Это то, что я сделал, и это сработало для меня.