Стандартные Java-карты, такие как вездесущий HashMap
, в конечном итоге ограничены доступной оперативной памятью. Прочтите эту статью и узнайте, как создавать Java-карты практически неограниченных размеров, даже превышающих объем оперативной памяти целевой машины.
Встроенные реализации Map, такие как HashMap
и ConcurrentHashMap
работают нормально, пока они относительно малы. Во всех случаях они ограничены доступной кучей и, следовательно, в конечном итоге доступным объемом оперативной памяти. ChronicleMap
может хранить свое содержимое в файлах, что позволяет обойти это ограничение, открывая возможности для отображений размером в терабайты, как показано в этой второй статье серии статей о CronicleMap
.
Узнайте больше об основах CronicleMap
в моей предыдущей первой статье .
Сопоставление файлов
Сопоставление файла выполняется путем вызова createPersistedTo()
в конструкторе ChronicleMap, как показано в методе ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
private static Map<Long, Point> createFileMapped() { try { return ChronicleMap .of(Long. class , Point. class ) .averageValueSize( 8 ) .valueMarshaller(PointSerializer.getInstance()) .entries(10_000_000) .createPersistedTo( new File( "my-map" )); } catch (IOException ioe) { throw new RuntimeException(ioe); } } |
Это создаст карту, которая будет размещать свой контент в отображенном в памяти файле с именем «my-map», а не в прямой памяти. В следующем примере показано, как мы можем создать 10 миллионов объектов Point
и сохранить их все в карте с отображением файлов:
01
02
03
04
05
06
07
08
09
10
11
12
|
final Map<Long, Point> m3 = LongStream.range( 0 , 10_000_000) .boxed() .collect( toMap( Function.identity(), FillMaps::pointFrom, (u, v) -> { throw new IllegalStateException(); }, FillMaps::createFileMapped ) ); |
Следующая команда показывает вновь созданный файл:
1
2
|
Pers-MacBook-Pro:target pemi$ ls -lart my-map -rw-r--r-- 1 pemi staff 330305536 Jul 10 16 : 56 my-map |
Как видно, размер файла составляет около 33 МБ, поэтому каждая запись занимает в среднем 33 байта.
Упорство
Когда JVM завершает работу, сопоставленный файл все еще там, что позволяет легко подобрать ранее созданную карту, включая ее содержимое. Это работает как элементарная сверхбыстрая база данных. Вот как мы можем начать с существующего файла:
1
2
3
4
5
6
|
return ChronicleMap .of(Long. class , Point. class ) .averageValueSize( 8 ) .valueMarshaller(PointSerializer.getInstance()) .entries(10_000_000) .createOrRecoverPersistedTo( new File( "my-map" )); |
Map
будет доступна напрямую, включая ее предыдущий контент.
Карта Java, превышающая ограничение ОЗУ
Одним интересным аспектом отображаемых в память файлов является то, что они могут превышать ограничения как кучи, так и памяти. Логика сопоставления файлов гарантирует, что используемые в данный момент детали загружаются в ОЗУ по требованию. Логика отображения также сохранит последние части доступной отображенной памяти в физической памяти для повышения производительности. Это происходит за кулисами и не должно управляться самим приложением.
Мой настольный компьютер — более старый MacBook Pro с 16 ГБ памяти (да, я знаю, что это отстой). Тем не менее, я могу выделить Map
с 1 миллиардом записей, потенциально занимающих 33 * 1 000 000 000 = 33 ГБ памяти (мы помним, что каждая запись занимала в среднем 33 байта). Код выглядит так:
1
2
3
4
5
6
|
return ChronicleMap .of(Long. class , Point. class ) .averageValueSize( 8 ) .valueMarshaller(PointSerializer.getInstance()) .entries(1_000_000_000) .createPersistedTo( new File( "huge-map" )); |
Несмотря на то, что я пытаюсь создать карту Java с удвоенным объемом оперативной памяти, код работает без сбоев, и я получаю этот файл:
1
2
|
Pers-MacBook-Pro:target pemi$ ls -lart | grep huge-map -rw-r--r-- 1 pemi staff 34573651968 Jul 10 18 : 52 huge-map |
Само собой разумеется, вы должны убедиться, что файл, на который вы отображаете, расположен в файловой системе с высокой производительностью произвольного доступа. Например, файловая система, расположенная на локальном SSD.
Резюме
ChronicleMap может быть сопоставлен с внешним файлом
Сопоставленный файл сохраняется при выходе из JVM
Новые приложения могут забрать существующий сопоставленный файл
ChronicleMap может хранить больше данных, чем есть ОЗУ
Сопоставленные файлы лучше всего размещать в файловых системах с высокой производительностью произвольного доступа.
Смотреть оригинальную статью здесь: Java: ChronicleMap Part 2, Карты Super RAM Мнения, высказанные участниками Java Code Geeks, являются их собственными. |