#java #io #nio
#java #io #nio
Вопрос:
Я получаю следующее исключение при использовании FileChannel.map
Exception in thread "main" java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
at sun.nio.ch.FileChannelImpl.map(Unknown Source)
at niotest.NioTest.readUsingNio(NioTest.java:38)
at niotest.NioTest.main(NioTest.java:64)
Быстрый просмотр реализации OpenJDK показывает, что метод map(..) в FileChannelImpl
принимает size
тип long
в качестве входных данных. Но внутри тела он сравнивает его с Integer.MAX_VALUE
и выдает ошибку, если оно больше этого. Зачем принимать long
размер в качестве входных данных, но ограничивать его максимальной integer
длиной?
Кто-нибудь знает конкретную причину, стоящую за этой реализацией? или это какая-то ошибка?
Исходный URL -адрес — http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/nio/ch/FileChannelImpl.java
Я запускаю эту программу, используя 64-разрядную JRE на 64-разрядной Windows-2k8
Ответ №1:
Это не ошибка, связанная с конкретной реализацией. Размер определен в FileChannel.map как long, но…
size — размер области, подлежащей отображению; должен быть неотрицательным и не превышать целое число.MAX_VALUE
Все совместимые реализации JVM будут такими. Я подозреваю, что причиной является сочетание истории (кому понадобился бы доступ к файлу размером более 2 ГБ? 😉 и пытается продвинуть работу в более поздних версиях Java (будет проще разрешить значения больше Integer.MAX
, чем изменить тип данных с int
на long
.)
Многие люди находят это основанное на int мышление в Java API относительно любого файла очень запутанным и недальновидным. Но помните, Java начала разработку в 1995 году! Я уверен, что в то время 2 ГБ казались относительно безопасным значением.
Комментарии:
1. Реальные причины в том, что ByteBuffer.capacity ограничен областью int, NIO появился в 1.4, так что ничего похожего на ’95
2. @bestsss: Они выбрали
int
overlong
, что на тот момент было неадекватно.long
работает на Java с 0-го дня. (Все это на 32-разрядных машинах, где использование 64-разрядного числа было бы дорогостоящим .) И » да» , Java 1.4 была выпущена в феврале 2002 года, но NIO возникла с JSR 51, который официально запущен в январе 2000 года. (В 2000 году средний размер продаваемого жесткого диска составлял 10 ГБ? 20 ГБ?) И не будет преувеличением предположить, что первоначальное зарождение JSR 51 началось за пинтой пива между парой талантливых инженеров задолго до этого. Наверняка не позднее конца 1999 года.3. насколько я помню, для жесткого диска это примерно 80 ГБ, а java была нацелена на большое железо solaris.
File.length()
существуетlong
с момента создания java. Выборint
имеет больше общего с внутренней оптимизацией и предсказаниями ветвлений в процессорах. Например,for(long i=....)
никогда не оптимизируется и не развертывается … и вы хотите, чтобы циклы над ByteBuffer устраняли проверку диапазона и разворачивали.4.Я сказал «среднее», а не «максимальное».en.wikipedia.org/wiki/File:Hard_drive_capacity_over_time.svg (Удивительно, как быстро числа кажутся такими маленькими. Я покупаю хранилище с килобайтных дней…Это потрясающе.) Я думаю, что моя точка зрения остается в силе:
int
законченаlong
, потому что это имело смысл для времени. Вы можете поспорить по поводу 1995 против 1999, но это не преувеличение.5. О, и Java в то время также была нацелена на «запись один раз, запуск в любом месте … включая графический интерфейс» … а не только на тяжелый набор Sun.
Ответ №2:
Емкость ByteBuffer ограничена целым числом.MAX_VALUE, поэтому нет способа отобразить что-либо большее, чем это.
Посмотрите на: MappedByteBuffer map(MapMode mode, long position, long size)
position
должно быть длинным по очевидным причинам.
size
необязательно быть длинным, но в любом вычислении его нужно увеличивать — например, position size должно быть положительным значением long. Отображение операционной системы действительно может использоваться long
для переноса отображения, map
функции (mmap) может потребоваться отобразить больше целого числа.MAX_VALUE для сохранения размера страницы, но ByteBuffer просто не может это использовать.
В целом, int
дизайн Java заложен очень глубоко, и в нем нет size_t
типа, похожего на C, массовое использование long
вместо int снизит производительность. Итак, в конце: если вам нужны карты объемом более 2 ГБ, просто используйте больше одного байт-буфера.