Java создает байтовый массив, размер которого представлен длинным

Я пытаюсь создать байтовый массив, размер которого имеет тип long. Например, представьте себе это как:

long x = _________;
byte[] b = new byte[x]; 

По-видимому, вы можете указать только int для размера массива байтов.

Прежде чем кто-нибудь спросит, зачем мне такой большой массив байтов, я скажу, что мне нужно инкапсулировать данные форматов сообщений, которые я не пишу, и один из этих типов сообщений имеет длину беззнакового int (long в Java).

Есть ли способ создать этот массив байтов?

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


person jbu    schedule 01.07.2009    source источник
comment
unsigned int на большинстве 32-битных архитектур имеет только на один бит больше, чем int в java. Java long - 64-битный и не подходит для индекса массива.   -  person Jherico    schedule 02.07.2009
comment
Я понимаю это, но я не знаю способа полностью представить объем данных, указанных в сообщении, без реализации моего собственного типа данных.   -  person jbu    schedule 02.07.2009


Ответы (5)


(Возможно, это немного поздно для OP, но все же может быть полезно для других)

К сожалению, Java не поддерживает массивы с более чем 2 31 −1 элементом. Максимальное потребление составляет 2 ГиБ для массива byte[] или 16 ГиБ для массива long[].

Хотя в данном случае это, вероятно, неприменимо, но если массив будет разреженным, вы можете уметь обойтись без использования ассоциативной структуры данных, такой как Map, чтобы каждое использованное смещение соответствовало соответствующему значению. Кроме того, Trove предоставляет более эффективную с точки зрения памяти реализацию для хранения примитивных значений, чем стандартные коллекции Java.

Если массив не является разреженным и вам действительно действительно нужен весь большой двоичный объект в памяти, вам, вероятно, придется использовать двумерную структуру, например с Map совпадающими смещениями по модулю 1024 в правильный массив размером 1024 байта. Такой подход может быть более эффективным с точки зрения памяти даже для разреженных массивов, поскольку соседние заполненные ячейки могут использовать одну и ту же запись Map.

person thkala    schedule 28.05.2012

byte[] с размером максимального 32-битного целого числа со знаком потребует 2 ГБ непрерывного адресного пространства. Не стоит пытаться создать такой массив. В противном случае, если размер на самом деле не такой большой (а это просто больший тип), вы можете безопасно преобразовать его в int и использовать его для создания массива.

person mmx    schedule 01.07.2009
comment
Предположительно, исходный вопросник не использует 32-разрядную JVM. Массив int [] с 2 ^ 32 байтами можно построить ... - person Tom Hawtin - tackline; 02.07.2009
comment
на самом деле максимальное значение - 31-битное целое число, поскольку типы java подписаны. Так что 2 гига примерно. - person jbu; 02.07.2009
comment
jbu: Ой. Ты прав. Очевидно, он также доступен в 64-битном процессе, но я хотел сказать, что он слишком большой, и если вы действительно создаете такой большой массив, вы, скорее всего, идете неправильным путем. - person mmx; 02.07.2009
comment
mehrdad: Я не знаю, я иду неверным путем ... опять же, это тип сообщения, с которым я работаю, который может быть настолько большим (теоретически). Кажется, что ошибается тот парень, который создал этот тип сообщения. Я не знаю, использует ли он полный размер своего сообщения, но мне кажется, что я хотел бы поддержать его сообщение, а не выбрасывать байты (даже если он их использует). - person jbu; 02.07.2009
comment
Если вы действительно ожидаете, что сообщение будет такого большого размера, вам следует использовать какой-то механизм буферизации, чтобы вы не загружали все сразу в память. Я просто попытался создать массив из 2 ^ 30 байт (Integer.MAX_VALUE / 2) в 64-битной JVM, и он выдает OutOfMemoryError. - person mmx; 02.07.2009
comment
да, я считаю, что это ... переполнение стека :) Думаю, тогда мне нужно выбросить байты или спросить этого парня, намерен ли он использовать все эти байты. - person jbu; 02.07.2009
comment
jbu: На самом деле он не создается в стеке. Не хватает места в куче Java. Я мог бы создать Integer.MAX_VALUE / 4 байта в 64-битной версии и намного меньше (совсем не то) в 32-битной. Вам действительно стоит подумать о буферизации, если вы ожидаете, что сообщение будет больше пары сотен мегабайт. - person mmx; 02.07.2009
comment
Как человек, у которого есть компьютер с 32 ГБ памяти, я не вижу проблемы с выделением 2 ГБ непрерывной памяти ... В конечном итоге это будет искусственное ограничение, которое необходимо изменить. - person Jason; 15.09.2013

Вероятно, вам следует использовать поток для чтения ваших данных и другой для их записи. Если вам понадобится доступ к данным позже в файле, сохраните их. Если вам нужен доступ к чему-то, с чем вы еще не сталкивались, вам нужна двухпроходная система, в которой вы проходите один раз и сохраняете «материал, который вам понадобится для второго прохода, а затем проходите снова».

Так работают компиляторы.

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

Класс контейнера будет иметь массив байтовых массивов, но извне все обращения кажутся непрерывными. Вы просто запросите байт 49874329128714391837, и ваш класс разделит ваш Long на размер каждого байтового массива, чтобы вычислить, к какому массиву получить доступ, а затем использовать остаток для определения байта.

У него также могут быть методы для хранения и извлечения «фрагментов», которые могут охватывать границы байтового массива, что потребует создания временной копии, но затраты на создание нескольких временных массивов будут более чем компенсированы тем фактом, что вы не используете У меня нет выделенного заблокированного места в 2 ГБ, что, как я думаю, может просто испортить вашу производительность.

Изменить: ps. Если вам действительно нужен произвольный доступ и вы не можете использовать потоки, тогда реализация содержащего класса является очень хорошей идеей. Это позволит вам на лету менять реализацию с однобайтового массива на группу байтовых массивов на файловую систему без каких-либо изменений в остальной части вашего кода.

person Bill K    schedule 02.07.2009
comment
Сомневаюсь, что даже в этом случае у вас получится выделить такой объем памяти. Не говоря уже о long, вторая строка вызывает исключение в 64-битной JRE на моем компьютере: byte [] a1 = new byte [Integer.MAX_VALUE / 4]; byte [] a2 = новый байт [Integer.MAX_VALUE / 4]; Ему придется использовать какой-то буфер в памяти, если он имеет дело с таким большим объемом данных. - person mmx; 02.07.2009
comment
Вот почему я предложил небольшой класс, который можно использовать для изменения реализации на лету. Конечно, следует использовать потоковую передачу, если это вообще возможно (и это абсолютно должно быть возможно!), Но в противном случае можно было бы использовать какой-то алгоритм кэширования с меньшими блоками, удерживаемыми мягкими ссылками. - person Bill K; 02.07.2009

Это не сразу поможет, но создание массивов большего размера (с помощью long) - это предлагаемое изменение языка для Java 7. Ознакомьтесь с предложениями Project Coin для получения дополнительной информации

person Brian Agnew    schedule 02.07.2009

Один из способов «сохранить» массив - записать его в файл, а затем получить к нему доступ (если вам нужно обращаться к нему как к массиву) с помощью RandomAccessFile. API для этого файла использует long как индекс в файле вместо int. Это будет медленнее, но с меньшей нагрузкой на память.

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

person Kathy Van Stone    schedule 02.07.2009