Есть ли реализация ByteBuffer, которая позволяет динамически расти и расширяет java.nio.ByteBuffer? - PullRequest
1 голос
/ 16 июня 2019

В моем коде есть java.nio.ByteBuffer:

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

Я хочу иметь возможность поменять его на месте для новой реализации ByteBuffer (то есть он должен расширять java.nio.ByteBuffer) так что он будет перераспределять, копировать и отбрасывать предыдущий маленький ByteBuffer изнутри, чтобы обеспечить плавное динамическое увеличение.

Я не могу просто иметь оболочку, потому что она должна бытьa java.nio.ByteBuffer.

Это должно быть что-то вроде этого:

ByteBuffer bb = new MyImplementationOfByteBufferThatExtendsByteBuffer(1024);

Кто-нибудь видел или делал это?Возможно ли это?

Просто хочу заметить, что если бы java.nio.ByteBuffer был интерфейсом вместо абстрактного класса, это было бы тривиально реализовать.Как гласит старая поговорка, предпочитает интерфейсы абстрактным классам , если вам нужна гибкость.

Ответы [ 2 ]

1 голос
/ 16 июня 2019

Нет, этого не существует, и не может существовать, не нарушая контракт суперкласса ByteBuffer Буфер :

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

  • Емкость буфера - это количество элементов, которые он содержит.Емкость буфера никогда не бывает отрицательной и никогда не меняется.

Поэтому, если вы разрешите «плавное динамическое увеличение», ByteBuffer больше не будет действовать как буфер.Это также верно независимо от интерфейсов и абстрактных классов : ни подклассы, ни реализации интерфейса не должны нарушать инварианты, определенные в расширяемых ими классах.В конце концов, потребители вашего HypotheticalGrowingByteBuffer могут рассчитывать на фиксированную емкость буфера для кэширования одного вызова на capacity(), который в противном случае был бы определен, чтобы не изменяться.

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

Тем не менее, Buffer определяет изменяемую концепцию limit, где большой первоначально-выделенный буфер может иметь искусственно ограниченную доступность.Вы можете использовать это, чтобы ограничить большой буфер, чтобы начать с малого, а затем расти, хотя рост не будет «плавным»;она будет ограничена заданной вами исходной емкостью буфера.Если цель состоит в том, чтобы просто объединить меньшие буферы фиксированного размера, где общий общий размер является предсказуемым, может быть целесообразно сгенерировать их как части большего буфера, используя ByteBuffer.duplicate и устанавливая метку и предел для ограничения области записи.

0 голосов
/ 16 июня 2019

Я почти уверен, что преднамеренно , что байтовые буферы имеют фиксированную емкость.Я призываю вас не пытаться обойти это, как если бы это был недостаток дизайна.Примите это и примите это как целенаправленное ограничение.

Если вы позволите ByteBuffers расти, то у compact() больше не будет предсказуемого максимального времени выполнения.Чем больше размер вашего буфера, тем больше времени потребуется для его сжатия.Я столкнулся именно с этой проблемой в моей библиотеке сокетов NIO.У меня выросли внутренние буферы для размещения больших инъекций данных, и следствием этого стало замедление производительности пропорционально тому, сколько данных было буферизовано.

Например, кто-то может попытаться отправить 100 МБ данных за один раз, поэтому ясохранит эти данные в одном байтовом буфере размером 100 МБ.Код обработки может обрабатывать только около 32 КБ за раз, поэтому он извлекает из буфера 32 КБ данных, а затем сжимает их.Затем еще 32 КБ и еще одно уплотнение.Он будет продолжать чтение и сжатие до тех пор, пока не будет опустошен буфер.

Каждое сжатие является операцией O (n), и я выполнял O (n) многих из них, что привело к общему времени выполнения O (n *).1010 * 2 ).Действительно плохие новости.Я заметил проблему, когда буферы становились настолько большими, что запросы ввода-вывода начинались по тайм-ауту, потому что поток ввода-вывода тратил все свое время на сжатие ByteBuffers.

Решение: Если вы хотите динамическийбуферы, создайте Queue<ByteBuffer>.Очередь может увеличиваться и вмещать неограниченное количество байтовых буферов, в то время как каждый буфер остается фиксированного размера.Это позволит вашему приложению масштабироваться правильно, не сталкиваясь с проблемой O (n 2 ).

...