Область кучи является одной из наиболее важных частей архитектуры JVM, поскольку в ней хранятся все объекты, созданные в экземпляре JVM, однако в некоторых случаях удобно размещать их за ее пределами. В этом посте мы увидим, как этого можно достичь, и некоторые реализации в этом отношении.
Вступление
Во-первых, давайте кратко рассмотрим архитектуру JVM.
Как мы видим, куча находится в области данных среды выполнения, которая содержит области, используемые во время выполнения программы, некоторые из них для каждого потока, а другие уникальны для экземпляра JVM, такого как куча. Необходимо учитывать сборщик мусора, поскольку он является ключом к пониманию того, как управляется память в куче.
Формальным определением области кучи является:
Виртуальная машина Java имеет кучу, которая является общей для всех потоков виртуальной машины Java. Куча – это область данных среды выполнения, из которой выделяется память для всех экземпляров классов и массивов. Куча создается при запуске виртуальной машины. Кучное хранилище для объектов освобождается автоматической системой управления хранилищем (известной как сборщик мусора ); объекты никогда не освобождаются явно. Виртуальная машина Java не предполагает определенного типа автоматической системы управления хранилищем, и метод управления хранилищем может быть выбран в соответствии с системными требованиями разработчика. Куча может быть фиксированного размера или может быть расширена в соответствии с требованиями вычисления и может быть сокращена, если большая куча становится ненужной. Память для кучи не обязательно должна быть непрерывной. Спецификация JVM
Зная, что все данные, хранящиеся в куче, подчиняются сборщику мусора, если данные, хранящиеся в куче, станут огромными, время, затрачиваемое сборщиком мусора, будет пропорционально выше, и здесь мы можем задаться вопросом, почему это может повлиять на нас? Что ж, у каждого сборщика мусора есть свой метод очистки кучи, но у всех них есть что-то общее, механизм Остановки мира , который означает, что в какой-то момент все потоки приложения будут приостановлены до тех пор, пока сборщик мусора не обработает все объекты в куче.
Тем не менее, в то время как алгоритмы сборщика мусора отлично справляются с очисткой в сверхбыстрое время, когда мы имеем дело с приложениями, работающими почти в режиме реального времени, у нас нет возможности использовать эти паузы или когда доступная физическая память меньше, чем требуется, то есть когда можно выгрузить эти данные из кучи.
Память вне кучи
Память вне кучи относится к памяти, выделенной непосредственно операционной системе, она может быть частью той же физической памяти или/и на основе доступа к диску, например файлы с отображением памяти . При выводе данных из JVM для записи и чтения этих данных необходима сериализация, а производительность будет зависеть от буфера, процесса сериализации и скорости диска (если применимо).
Выгоды
- Снижение давления на сбор мусора.
- Большой объем памяти, в зависимости от реализации.
- Память, общая для всех виртуальных машин, присутствующих в ОС.
Соображения
- Влияние процесса сериализации на производительность
- Ручное управление памятью сложно и подвержено ошибкам (задача для разработчиков C 😅 ).
Использование
Способ использования памяти вне кучи зависит от разработчиков и бизнес-модели, либо создания собственной реализации с использованием Java NIO API, которые позволяют нам выделять память вручную, либо использования любой из реализаций, уже имеющихся на рынке.
В этом посте мы рассмотрим в общем обзоре библиотеку, которая реализует некоторые из наиболее распространенных структур данных, используемых в java.
- Карта хроники : Карта хроники – это хранилище значений ключей в памяти, предназначенное для приложений с низкой задержкой и/или многопроцессорных приложений.
Давайте проведем простой тест, в котором сценарий представляет собой приложение, которое обрабатывает несколько миллионов чисел и помещает их в заданную структуру данных, чтобы впоследствии суммировать их.
- Репозиторий проекта: GitHub – тесты вне кучи
- Максимальный размер кучи: 2 ГБ
- JDK: 64-разрядная серверная виртуальная машина OpenJDK Microsoft-18724
- Физическая память: 16 ГБ
long sumNumbers(Setnumbers) throws InterruptedException { for (int i = 0; i < 30_000_000; i++) { numbers.add(random.nextLong()); if (i % 1_000_000 == 0) Thread.sleep(1000); // To have time to check jconsole } return numbers.stream().reduce(0L, Long::sum); }
public static void main(String[] args) throws InterruptedException { var start = Instant.now(); new Main(). executeTest(); var end = Instant.now(); var timeMilli = end.toEpochMilli() - start.toEpochMilli(); System.out.println("Time to get finished in ms: " + timeMilli); }
Реализация Java-хэш-набора
Первым тестом будет использование простой реализации хэш-набора
void executeTest() throws InterruptedException { final Setset = new HashSet<>(); System.out.println(sumNumbers(set)); }
Мы можем сказать, что для завершения потребовалось около 58 тыс. ~ 59 тыс. миллисекунд.
Реализация набора хроник
Набор хроник предоставляет конструктор, которому требуется тип и максимальное количество записей для выделения памяти на их основе.
void executeTest() throws InterruptedException { final var set = ChronicleSetBuilder.of(Long.class) .entries(30_000_000) .create(); return sumNumbers(set); }
Мы можем сказать, что для завершения потребовалось около 52 тыс. ~ 53 тыс. миллисекунд, а также заметить изменения в используемой памяти кучи и уменьшение влияния GC.
Выводы
Память вне кучи – хороший вариант, когда данные, хранящиеся в куче, огромны, и нам нужно сократить время, затрачиваемое сборщиком мусора, а также когда приложение использует больше памяти, чем доступно физически, и использование дискового пространства является вариантом. Однако стоит напомнить, что непосредственная работа с выделением памяти – непростая задача, и это может привести к возникновению сложных проблем.
В каких еще случаях, по вашему мнению, можно использовать память вне кучи?
Если вам понравился этот пост, вы можете найти больше в https://jeisson.dev/blog/ и подписывайтесь на меня в твиттере @jeissonflorez29 👋
Оригинал: “https://dev.to/jeissonflorez29/off-heap-memory-in-java-4dd1”