2011-01-18 2 views
8

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

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

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

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

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

  1. Byte Buffers and Non-Heap Memory - мистер Грегори, кажется, быть грамотным в Java NIO.

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

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

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

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

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

~ 28 сек для RAF! ~ 0.2 сек. Для FBM!

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

Ok, теперь после всех тех вещей, которые я узнал есть один вопрос и 1 дилемма :)

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

Дилемма: В зависимости от ваших ответов на вопрос ...

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

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

Редактировать: Вот еще один вопрос. Некоторые из вас говорят, что сопоставление не копирует файл в MappedByteBuffer. Итак, почему я не могу сопоставить 1GB-файл, тогда я получаю сообщение «не удалось отобразить» ...

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

Спасибо :)

ответ

3

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

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

Источник: Wikipedia

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

+0

Если вы говорите, что MappedByteBuffer является указателем на HD, то как он достигает таких хороших результатов в бенчмаркинге? Единственная возможная функция ускорения в IO, которую я лично знаю, - ДОСТУП К ДИСКУ КАК МЕНЬШЕ КАК ВОЗМОЖНО, и единственным решением здесь является буферизация. Опять же, если вы достаточно грамотны в этом отношении, будьте более подробными. –

+0

@Haroogan Я цитирую из этой статьи: «разница почти полностью связана с переключением контекста ядра» – someguy

+0

Вы, должно быть, шутите, обращаясь к javadoc, не так ли? Coz, нет никакой конкретной информации, о которой я прошу. У меня до сих пор нет прямых ответов или правильных идей и комментариев о возможных решениях. –

2

Для 220 Мб файла я Карта памяти все это в виртуальную память. Причина FBM настолько велика, что на самом деле она не считывает данные в память, а просто делает ее доступной.

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

+0

Что вы подразумеваете под "наличием"? Могут быть только два варианта: файл полностью скопирован в MappedByteBuffer (максимальный размер составляет 2 ГБ для 32-разрядных систем), или MappedByteBuffer просто эмулирует этот файл с помощью фоновой буферизации, прогнозирования логики или любого другого ... Так как я попытался отобразить 1 ГБ файл, и это не удалось сделать, я должен сделать вывод, что его сопоставление, похоже, копирует весь файл в MappedByteBuffer ... или я все еще не прав? Пожалуйста, будьте более подробными в своих ответах. –

+0

При сопоставлении ОС отображает файл в виртуальную память. Страницы (обычно 4 Кбайт) файла приводятся в память при их чтении/записи и медленном обращении на диск. (Или когда вы нажимаете флеш). Невозможно прочитать 220 МБ-файл в памяти за 0.2 секунды. Я не уверен, почему файл размером 1 ГБ не был отображен, если вы не используете 32-разрядную JVM. –

+0

Да, я использую 32-разрядную JVM, поэтому я не понимаю, почему сопоставление файлов 1GB не удается ... любые идеи? В настоящее время меня интересует только чтение, поэтому мне не нужен флеш и т. Д. Вы только что сказали, что ОС загружает 4 КБ страниц в виртуальную память, но вы видите, что это то, что я сказал раньше, я. е. MappedByteBuffer просто эмулирует этот файл, используя медленную логику буферизации фона, которую я не могу контролировать. Правильно? –

1

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

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

Смежные вопросы