Почему FileChannel.map занимает до целого числа.МАКСИМАЛЬНОЕ ЗНАЧЕНИЕ данных?

#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 over long , что на тот момент было неадекватно. 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 ГБ, просто используйте больше одного байт-буфера.