Как механизм Class Data Sharing сокращает время запуска Java-приложения при повторном использовании одного набора классов?
Class Data Sharing (CDS) заранее сохраняет часть уже обработанных данных о классах в архиве, который JVM может отображать в память при запуске. Благодаря этому сокращаются повторные затраты на загрузку, связывание и подготовку классов, а некоторые страницы памяти могут совместно использоваться несколькими JVM-процессами.
CDS не означает, что все классы и объекты приложения загружаются из готового снимка. Классы, не соответствующие архиву или ограничениям CDS, JVM обрабатывает обычным способом.
Обычный запуск JVM требует заново найти классы, прочитать их байткод, проверить структуру, выполнить связывание и подготовить внутренние структуры представления классов. Для приложений с большим количеством библиотек это увеличивает время старта и расход памяти, особенно когда на одном сервере работают несколько похожих JVM.
CDS появился как способ вынести часть повторяющейся работы из запуска и предоставить нескольким процессам общий архив подготовленных данных. Позднее подход был расширен для более гибкого включения прикладных классов через AppCDS.
Без CDS несколько экземпляров одного приложения независимо выполняют одинаковую работу по подготовке классов. Это особенно заметно в короткоживущих сервисах, инструментах командной строки и средах с большим количеством параллельных JVM.
Неверно считать, что подключение CDS автоматически ускорит любой запуск. Эффект зависит от совпадения фактического набора классов с архивом, режима загрузки, версии JVM, параметров запуска и доли классов, которые удалось использовать из архива.
При создании архива JVM анализирует классы и сохраняет пригодные для повторного использования данные о них в специальном файле. При последующем запуске JVM отображает архив в адресное пространство процесса и использует его содержимое вместо полного повторения части операций подготовки.
Архив обычно содержит данные о классах, их метаданные и связанные структуры, но не произвольные экземпляры объектов приложения. Статические состояния, содержимое коллекций, соединения и другие изменяемые данные не становятся общими объектами между процессами.
Совместное отображение возможно только для данных, которые безопасно разделять. Если процесс или JVM должны изменить страницу, применяется механизм copy-on-write: процесс получает собственную изменяемую копию. Поэтому CDS может уменьшать физический расход памяти, но не гарантирует, что весь архив будет постоянно совместным.
Использование архива проверяется при запуске. Несовместимая версия классов, отличающийся путь поиска, неподходящий загрузчик, трансформация байткода или иные изменения могут привести к тому, что конкретный класс будет загружен обычным способом. Это не обязательно ошибка: JVM может частично использовать CDS, а для остальных классов выполнить стандартную загрузку.
CDS не меняет правило идентичности типов: классы с одинаковым именем, загруженные разными загрузчиками, по-прежнему являются разными типами. Он также не отменяет инициализацию классов и не гарантирует, что пользовательский код статического инициализатора будет выполнен заранее.
При оценке эффекта нужно сравнивать одинаковые сценарии запуска и проверять фактическое использование архива по диагностическим логам JVM. Важны не только wall-clock время, но и RSS, committed-память, количество загруженных классов и доля классов, взятых из архива.
Команда запускает много короткоживущих экземпляров Java-сервиса с неизменным набором библиотек. Без оптимизации каждый экземпляр тратит заметную часть времени старта на подготовку классов, а суммарный расход памяти растёт из-за повторения одинаковых данных.
Вариант без CDS прост в эксплуатации, но не уменьшает повторную работу. Полный заранее подготовленный образ запуска может дать больший эффект, однако он сложнее в сопровождении и чувствителен к изменениям окружения. AppCDS требует этапа создания и проверки архива, зато лучше подходит для стабильного набора прикладных классов.
Выбранный вариант — включить CDS, сформировать архив для воспроизводимого запуска и проверять его использование после обновлений. Если после изменения зависимостей архив перестал применяться, сервис не должен считаться сломанным: сначала сравнивают время старта и диагностические данные, затем при необходимости пересоздают архив. Результат — сокращение повторной работы на старте и потенциальное уменьшение физического расхода памяти при нескольких похожих JVM, но не универсальное ускорение всех приложений.
1. Делает ли CDS классы доступными до их загрузки загрузчиком приложения?
Нет. Архив содержит подготовленные данные, но JVM всё равно должна установить связь класса с конкретным ClassLoader и проверить применимость архивированной информации. CDS не нарушает модель загрузчиков и не позволяет одному загрузчику использовать класс другого загрузчика как тот же самый тип.
2. Гарантирует ли CDS одинаковое ускорение после любого изменения classpath?
Нет. Архив создаётся для определённого набора условий. Изменение версии библиотеки, порядка поиска, параметров запуска или трансформация байткода может сделать часть записей непригодной. JVM обычно откатывается к обычной обработке соответствующих классов, поэтому эффект нужно измерять после обновлений.
3. Уменьшает ли CDS размер heap приложения?
Не напрямую. CDS в первую очередь помогает переиспользовать данные, связанные с классами, и может уменьшать затраты памяти вне обычных объектов приложения. Экземпляры объектов, содержимое коллекций и большая часть прикладного heap по-прежнему создаются отдельно в каждом процессе.