Изменить: то, что вы хотите, это FileInputStream.getChannel (). Map (), затем адаптировать его к InputStream, а затем подключить его к DataInputStream.

тоящее время я разрабатываю приложение для 3D-графики, используяJOGL (Java OpenGL привязка). Вкратце, у меня есть огромный двоичный файл ландшафта. Из-за его размера, я должен передавать потоки ландшафта во время выполнения. Поэтому мы явно видим проблему произвольного доступа. Я уже закончил первую (и грязную :)) реализацию (возможно, она многопоточная), где я использую глупый подход ... Вот его инициализация:

dataInputStream = new DataInputStream(new BufferedInputStream(fileInputStream,4 * 1024);
dataInputStream.mark(dataInputStream.available());

И когда мне нужно прочитать (поток) специальный кусок (я уже знаю его «смещение» в файле), я выполняю следующее (позор мне :)):

dataInputStream.reset();
dataInputStream.skipBytes(offset);
dataInputStream.read(whatever I need...);

Поскольку у меня было мало опыта, это было первое, о чем я мог подумать :) Итак, до сих пор я прочитал 3 полезные и довольно интересные статьи (я предлагаю вам прочитать их, возможно, если вы заинтересованы в этой теме)

Байт-буферы и память без кучи - Г-н Грегори, кажется, грамотный в Java NIO.

Совет по Java: как быстро читать файлы [http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly] - Это интересный тест.

Статьи: Настройка производительности ввода-вывода Java [http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/] - Простые рекомендации Sun, но, пожалуйста, прокрутите вниз и посмотрите там раздел «Произвольный доступ»; они показывают простую реализацию RandomAccessFile (RAF) с улучшением само-буферизации.

Г-н Грегори предоставляет несколько файлов * .java в конце своей статьи. Одним из них является сравнительный анализ между FileChannel + ByteBuffer + Mapping (FBM) и RAF. Он говорит, что он заметил 4-кратное ускорение при использовании FBM по сравнению с RAF. Я провел этот тест в следующих условиях:

Смещение (например, место доступа) генерируется случайным образом (в области видимости файла, например, 0 - file.length ());Размер файла составляет 220 МБ;1 000 000 обращений (75% читает и 25% пишет)

Результаты были ошеломляющими:

~ 28 сек для RAF!~ 0,2 сек для FBM!

Тем не менее, его реализация RAF в этом тесте не имеет собственной буферизации (3-я статья рассказывает об этом), поэтому я думаю, что это вызов метода «RandomAccessFile.seek», который так сильно снижает производительность.

Хорошо, теперь после всего того, что я узнал, есть 1 вопрос и 1 дилемма :)

Вопрос: Когда мы отображаем файл с помощью «FileChannel.map», Java копирует все содержимое файла в MappedByteBuffer? Или это просто подражать? Если он копирует, то использование подхода FBM не подходит для моей ситуации, не так ли?

дилемма: Зависит от ваших ответов на вопрос ...

Если отображение копирует файл, то кажется, что у меня есть только 2 возможных решения:RAF + самобуферизация (тот, что из 3-й статьи) илииспользовать позицию в FileChannel (не с отображением) ... Какой из них будет лучше?

Если отображение не копирует файл, то у меня есть 3 варианта: два предыдущих иСам FBM.

редактироватьВот еще один вопрос. Некоторые из вас говорят, что отображение не копирует файл в MappedByteBuffer. Хорошо, тогда почему я не могу сопоставить файл 1 ГБ, я получаю сообщение "не удалось сопоставить" ...

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

Спасибо :)

Ответы на вопрос(3)

Решение Вопроса

данные не буферизируются. MappedByteBuffer ссылается на данные, используяуказатель, Другими словами, данные не копируются, это простосопоставляются в физическую память. УвидетьAPI документы если вы еще этого не сделали

Файл с отображением в памяти - это сегмент виртуальной памяти, которому была назначена прямая побайтная корреляция с некоторой частью файла или файлового ресурса. Этот ресурс обычно является файлом, который физически присутствует на диске, но также может быть устройством, объектом общей памяти или другим ресурсом, на который операционная система может ссылаться через дескриптор файла. Когда-то эта корреляция между файлом и пространством памяти позволяет приложениям обрабатывать отображенную часть, как если бы она была первичной памятью.

Источник:Википедия

Если вы собираетесь читать данные довольно часто, неплохо бы хотя бы кешировать некоторые из них.

 Alexander Shukaev18 янв. 2011 г., 23:41
Вы, должно быть, шутите, отсылая меня к Javadoc, не так ли? Потому что нет конкретной информации, которую я спрашиваю. У меня до сих пор нет прямых ответов или правильных идей и комментариев о возможных решениях.
 Alexander Shukaev19 янв. 2011 г., 18:41
Кажется, ты просто не понимаешь. Я попробую еще раз с примитивным вопросом. Просто скажи да или нет. Если я отображаю 1 ГБ файл, то MappedByteBuffer ёмкость = 1 ГБ, поэтому MappedByteBuffer действительно занимает 1 ГБ ОЗУ или просто эмулирует его?
 someguy18 янв. 2011 г., 22:50
@ Haroogan Я цитирую из этой статьи: «разница почти полностью связана с переключением контекста ядра»
 someguy19 янв. 2011 г., 17:16
@ Haroogan Прежде всего, открой глаза. Мой ответ достаточен, учитывая все, что вы хотели знать, было ли «отображение копирует файл». В самой первой строке javadoc говорится, что данные отображаются в память. Вы должны были спросить меня, что это значит, вместо того, чтобы называть мой ответ шуткой. Остальная часть моего ответа объясняет, что это такое, во всяком случае. Более того, я дал дополнительное предложение о том, как оптимизировать.
 Alexander Shukaev18 янв. 2011 г., 22:29
Если вы говорите, что MappedByteBuffer - это указатель на HD, то как он достигает столь хороших результатов в бенчмаркинге? Единственная возможная функция ускорения в IO, которую я лично знаю, - это ДОСТУП К ДИСКУ, КАК МЕНЬШЕ, КАК ВОЗМОЖНО, и единственным решением здесь является буферизация. Опять же, если вы достаточно грамотны в этом вопросе, пожалуйста, будьте более подробны.

что если вы запускаете программу, затем закрываете ее, а затем снова запускаете, она запускается намного быстрее во второй раз? Это происходит потому, что операционная система кэшировала части файлов, к которым был получен доступ при первом запуске, и не нуждается в доступе к диску для них. Отображение памяти в файле, по существу, позволяет программе получить доступ к этим буферам, таким образом сводя к минимуму копии, сделанные при его чтении. Обратите внимание, что отображение памяти в файле не приводит к тому, что он читается целиком в память; фрагменты, которые вы читаете, читаются с диска по требованию. Если ОС определяет, что памяти мало, она может решить освободить некоторые части сопоставленного файла из памяти и оставить их на диске.

Изменить: то, что вы хотите, это FileInputStream.getChannel (). Map (), затем адаптировать его к InputStream, а затем подключить его к DataInputStream.

наFBM настолько быстр, что фактически не читает данные в память, он просто делает их доступными.

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

 Alexander Shukaev19 янв. 2011 г., 18:43
Да, я использую 32-разрядную JVM, поэтому я не понимаю, почему не удается сопоставить файл размером 1 ГБ ... есть идеи? В настоящее время я заинтересован только в чтении, поэтому мне не нужно сбрасывать и т. Д. Вы только что сказали, что ОС загружает 4 КБ страницы в виртуальную память, но вы видите, это то, что я говорил раньше, т.е. е. MappedByteBuffer просто эмулирует этот файл, используя медленную логику фоновой буферизации, которой я не могу управлять. Правильно?
 Peter Lawrey19 янв. 2011 г., 20:50
Java использует базовое отображение ОС. В нем говорится, как это происходит, потому что это зависит от используемой вами ОС. Если вы хотите знать, как ваша ОС это делает, вам нужно прочитать документацию для вашей ОС.
 Alexander Shukaev18 янв. 2011 г., 21:41
Что вы подразумеваете под "доступным"? Вариантов может быть только 2: файл полностью копируется в MappedByteBuffer (максимальный размер составляет 2 ГБ для 32-разрядных систем) или MappedByteBuffer просто эмулирует этот файл, используя фоновую буферизацию, логику прогнозирования или что-то еще ... Так как я попытался отобразить 1 ГБ файл, и это не удалось сделать, я должен сделать вывод, что его сопоставление, кажется, копирует весь файл в MappedByteBuffer ... или я все еще не прав? Пожалуйста, будьте более подробны в своих ответах.
 Peter Lawrey19 янв. 2011 г., 09:38
При отображении ОС отображает файл в виртуальную память. Страницы (обычно 4 КБ) файла помещаются в память, когда вы их читаете / записываете, и медленно возвращаются на диск. (Или при принудительной очистке) Невозможно прочитать файл размером 220 МБ в памяти за 0,2 секунды. Я не уверен, почему не удалось сопоставить файл размером 1 ГБ, если вы не используете 32-разрядную JVM.
 Peter Lawrey19 янв. 2011 г., 20:47
32-разрядная JVM в 32-разрядной ОС может использовать только от 1,2 до 1,5 ГБ виртуальной памяти. 32-битная JVM в 64-битной ОС может получить доступ к большему. На Солярисе он может получить доступ к 3,5 ГБ. Самая большая 64-битная JVM, которую я видел, имеет доступ 768 ГБ. Ни то, ни другое не соответствует теоретическому пределу, но вы можете видеть, что 64-битная JVM является правильным инструментом для этой работы. Вы можете контролировать доступ к файлу в каком порядке, объем файла, который вы можете иметь в памяти, ограничен вашим оборудованием, скорость чтения файла также ограничена вашим оборудованием.

Ваш ответ на вопрос