Файлы, отображаемые в память, являются хорошим и часто игнорируемым инструментом. Я не буду вдаваться в подробности о том, как они работают (используйте сила Гугл Люк!), Но я быстро подытожу их достоинства
- ленивая загрузка и запись в кеш, предоставляемые операционной системой (вам не нужно писать свою собственную, и можно с уверенностью сказать, что операционная система работает хорошо)
- легкое чтение сложных двоичных данных (например, таких, в которых закодированы все виды относительных смещений)
- может использоваться в качестве очень высокопроизводительного механизма 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
Exception
in
thread
"main"
java.io.IOException: Input
/output
error
at 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
Exception
in
thread
"main"
java.io.IOException: The volume
for
a
file
has been externally altered so that the opened
file
is no longer valid
at 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)
Вывод: файлы с отображением в памяти великолепны — как очень острый нож — это здорово: с ними можно очень быстро делать отличные вещи, но они также могут порезать вам палец. Если вы хотите использовать отображенные в память файлы из-за преимуществ, которые они предлагают:
- быть готовым к краху. Иметь план, когда это произойдет (горячий резерв, теплый резерв, ничего не делать — все это допустимые варианты, но решите заранее)
- если вы хотите быть уверены, что данные находятся на диске, очистите их . Когда это вернется, вы можете (почти) быть уверены, что данные находятся на диске (мы не попадем в удивительный мир дисковых / контроллеров кэшей или виртуализированных серверов здесь).