Файлы, отображаемые в память, являются хорошим и часто игнорируемым инструментом. Я не буду вдаваться в подробности о том, как они работают (используйте сила Гугл Люк!), Но я быстро подытожу их достоинства
- ленивая загрузка и запись в кеш, предоставляемые операционной системой (вам не нужно писать свою собственную, и можно с уверенностью сказать, что операционная система работает хорошо)
- легкое чтение сложных двоичных данных (например, таких, в которых закодированы все виды относительных смещений)
- может использоваться в качестве очень высокопроизводительного механизма IPC
- записывается на диск, даже если ваш процесс падает (если ОС выживает)
- очень высокая скорость записи, потому что вы не блокируете (асинхронный сброс обеспечивается ОС), и вам не нужно входить в режим ядра
Однако при всей этой асинхронности мне было интересно: что произойдет в случае отказа диска? Как ОС может уведомить ваш процесс о том, что ей не удалось записать на диск то, что вы записали в память?
Немного поиска нашел ответы:
- Под Linux ваш процесс получает SIGBUS, когда ОС пытается записать память обратно на диск, но не удается
- Под Windows вы получите ошибку EXCEPTION_IN_PAGE_ERROR при следующем вызове функции ОС для дескриптора файла
Желая подтвердить информацию, я запустил программу быстрого тестирования , подключил жертвенный USB-накопитель к своему ноутбуку и сделал пару тестов. Выводы:
- Конечно же, Linux генерирует SIGBUS, а у Java (OpenJDK 1.7.0_51-b00) нет обработчика, что приводит к сбою процесса:
12345678
# A fatal error has been detected by the Java Runtime Environment:## SIGBUS (0x7) at pc=0x00007f9bb5042396, pid=26654, tid=140306951444224## JRE version: OpenJDK Runtime Environment (7.0_51) (build 1.7.0_51-b00)# Java VM: OpenJDK 64-Bit Server VM (24.45-b08 mixed mode linux-amd64 compressed oops)# Problematic frame:# v ~StubRoutines::jlong_disjoint_arraycopyС другой стороны, вы знаете , что что-то пошло ужасно неправильно, так как ваш процесс перестал быть. С другой стороны, вы можете не сразу (если вы не читали этот пост)
- Linux также может генерировать более «традиционные» ошибки, если вы попытаетесь очистить файл, например:
12345
Exceptioninthread"main"java.io.IOException: Input/outputerrorat sun.nio.ch.FileDispatcherImpl.force0(Native Method)at sun.nio.ch.FileDispatcherImpl.force(FileDispatcherImpl.java:76)at sun.nio.ch.FileChannelImpl.force(FileChannelImpl.java:376)at Main.main(Main.java:84) - Windows генерирует исключения только при повторной работе с файловым дескриптором (например, путем его сброса — как в Linux — но также и при создании новых отображений — чего-то, чего не было в Linux):
123456
Exceptioninthread"main"java.io.IOException: The volumeforafilehas been externally altered so that the openedfileis no longer validat sun.nio.ch.FileDispatcherImpl.size0(Native Method)at sun.nio.ch.FileDispatcherImpl.size(FileDispatcherImpl.java:96)at sun.nio.ch.FileChannelImpl.size(FileChannelImpl.java:307)at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:849)at Main.main(Main.java:64)
Вывод: файлы с отображением в памяти великолепны — как очень острый нож — это здорово: с ними можно очень быстро делать отличные вещи, но они также могут порезать вам палец. Если вы хотите использовать отображенные в память файлы из-за преимуществ, которые они предлагают:
- быть готовым к краху. Иметь план, когда это произойдет (горячий резерв, теплый резерв, ничего не делать — все это допустимые варианты, но решите заранее)
- если вы хотите быть уверены, что данные находятся на диске, очистите их . Когда это вернется, вы можете (почти) быть уверены, что данные находятся на диске (мы не попадем в удивительный мир дисковых / контроллеров кэшей или виртуализированных серверов здесь).