JEP 351: ZGC: Uncommit Unused Memory (Experimental)
ZGC: освобождение неиспользуемой памяти, Experimental (экспериментальная функция)
| Ответственный | Per Liden |
| Тип | Feature |
| Область | Implementation |
| Статус | Closed / Delivered |
| Выпуск | 13 |
| Компонент | hotspot / gc |
| Обсуждение | hotspot dash gc dash dev at openjdk dot java dot net |
| Трудоёмкость | S |
| Длительность | S |
| Зависит от | JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental) |
| Связан с | JEP 377: ZGC: A Scalable Low-Latency Garbage Collector (Production) |
| Рецензенты | Mikael Vidstedt, Stefan Karlsson |
| Одобрен | Mikael Vidstedt |
| Создан | 2019/03/08 10:35 |
| Обновлён | 2021/08/28 00:16 |
| Задача | 8220347 |
Аннотация
Доработать ZGC, чтобы он возвращал неиспользуемую память кучи операционной системе.
Мотивация
Сейчас ZGC не освобождает (uncommit) память и не возвращает её операционной системе, даже если эта память долго не используется. Такое поведение подходит не для всех типов приложений и сред, особенно для тех, где важен объём потребляемой памяти. Например:
-
Контейнерные среды, где ресурсы оплачиваются по мере использования.
-
Среды, где приложение может подолгу простаивать и при этом делит ресурсы со многими другими приложениями или конкурирует с ними за ресурсы.
-
Потребность приложения в объёме кучи может сильно меняться во время работы. Например, при запуске куче может требоваться больше памяти, чем позже, в установившемся режиме работы.
Другие сборщики мусора в HotSpot, например G1 и Shenandoah, уже умеют это делать, и некоторые категории пользователей считают эту возможность очень полезной. Те же пользователи были бы рады, если бы она появилась и в ZGC.
Описание
Куча ZGC состоит из набора областей кучи, называемых ZPages. С каждой ZPage связан переменный объём выделенной (committed) памяти кучи. Когда ZGC уплотняет кучу, ZPages освобождаются и помещаются в кэш страниц, ZPageCache. ZPages в кэше страниц готовы к повторному использованию для новых выделений памяти в куче; в этом случае они удаляются из кэша. Кэш страниц критически важен для производительности, поскольку выделение и освобождение памяти — дорогостоящие операции.
Набор ZPages в кэше страниц — это неиспользуемые части кучи, которые можно было бы освободить и вернуть операционной системе. Поэтому освободить память можно, просто вытеснив из кэша страниц удачно выбранный набор ZPages и освободив память, связанную с этими страницами. Кэш страниц уже хранит ZPages в порядке давности использования (least-recently-used, LRU) и с разделением по размеру (малые, средние и большие), поэтому сам механизм вытеснения ZPages и освобождения памяти относительно прост. Сложность в том, чтобы разработать политику, которая решает, когда пора вытеснить ZPage из кэша.
Простая политика — задать тайм-аут, или задержку, определяющую, сколько времени ZPage может находиться в кэше страниц, прежде чем будет вытеснена. У этого тайм-аута было бы разумное значение по умолчанию, которое можно переопределить параметром командной строки. Shenandoah GC использует подобную политику со значением по умолчанию 5 минут и параметром командной строки -XX:ShenandoahUncommitDelay=<milliseconds> для переопределения значения по умолчанию.
Политика вроде описанной выше может работать достаточно хорошо. Однако можно представить и более сложные политики, не требующие новых параметров командной строки. Например, эвристики, которые подбирают подходящее значение тайм-аута на основе частоты сборок мусора или каких-то других данных. Сначала мы реализуем простую политику с тайм-аутом и параметром -XX:ZUncommitDelay=<seconds>, а более сложную политику (если такая найдётся) добавим позже.
Освобождение памяти будет включено по умолчанию. Но что бы ни решила политика, ZGC никогда не должен освобождать память так, чтобы куча стала меньше своего минимального размера (-Xms). Это означает, что освобождение памяти фактически отключено, если JVM запущена с минимальным размером кучи (-Xms), равным максимальному размеру кучи (-Xmx). Также будет добавлен параметр -XX:-ZUncommit, чтобы явно отключать эту возможность.
Наконец, ZGC в Linux/x64 использует для размещения кучи файл в tmpfs или hugetlbfs. Для освобождения памяти, используемой этими файлами, нужен fallocate(2) с поддержкой FALLOC_FL_PUNCH_HOLE, которая впервые появилась в Linux 3.5 (tmpfs) и 4.3 (hugetlbfs). На более старых ядрах Linux ZGC должен работать как прежде, за исключением того, что освобождение памяти будет отключено.
Тестирование
-
Будут разработаны один или несколько тестов jtreg, проверяющих освобождение памяти.
-
С помощью существующих бенчмарков, таких как SPECjbb и SPECjvm, мы проверим, что при политике по умолчанию нет заметного ухудшения задержки или пропускной способности.