Что делает горячее развертывание «трудной проблемой»?

На работе у нас возникли проблемы с исключениями из « PermGen out of memory », и руководство команды решило, что это ошибка в JVM – что-то связанное с горячим развертыванием кода. Не объясняя много деталей, он отметил, что горячее развертывание – это «трудная проблема», настолько сложная, что даже .NET этого еще не делает.

Я нашел много статей, объясняющих горячее развертывание с высоты птичьего полета, но всегда не имеющих технических деталей. Может ли кто-нибудь указать мне на техническое объяснение и объяснить, почему горячее развертывание является «трудной проблемой»?

Когда class загружается, различные статические данные о classе хранятся в PermGen. Пока существует живая ссылка на этот экземпляр classа, экземпляр classа не может быть собран в мусор.

Я считаю, что часть проблемы связана с тем, должен ли GC удалять старые экземпляры classа из perm gen или нет. Как правило, каждый раз, когда вы горячо развертываете, в пул памяти PermGen добавляются экземпляры нового classа, а старые, которые теперь не используются, обычно не удаляются. По умолчанию Sun JVM не будут запускать сборку мусора в PermGen, но это может быть включено с дополнительными аргументами команды «java».

Поэтому, если вы быстро развернете достаточно времени, вы в конечном итоге исчерпаете пространство PermGen.

Если ваше веб-приложение не закрывается полностью, когда оно не развернуто – если оно, например, покидает stream, то все экземпляры classа, используемые этим веб-приложением, будут закреплены в пространстве PermGen. Вы передислоцируете и теперь имеете еще одну целую копию всех этих экземпляров classа, загруженных в PermGen. Вы отказываетесь от развертывания, и stream продолжает двигаться, закрепляя ДРУГОЙ набор экземпляров classа в PermGen. Вы передислоцируете и загружаете весь набор готовых копий … и в конечном итоге ваш PermGen заполняется.

Иногда вы можете исправить это:

  • Предоставление аргументов команды недавней Sun JVM для включения GC в PermGen и classов. Это: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  • Использование другой JVM, которая не использует фиксированный размер PermGen или что GC на загруженных classах

Но это поможет только в том случае, если ваше веб-приложение отключится полностью и чисто, не оставляя прямых ссылок на какие-либо экземпляры classа любого classа, загруженные загрузчиками Class для этого веб-приложения.

Даже это не обязательно устранит проблему из-за утечек загрузчика classа. (В некоторых случаях слишком много интернированных строк).

Ознакомьтесь со следующими ссылками для получения дополнительной информации (у двух полужирных есть хорошие диаграммы, чтобы проиллюстрировать часть проблемы).

  • Утечка загрузчика classа: страшное исключение «java.lang.OutOfMemoryError: PermGen space»
  • Неизвестное поколение: Пермь
  • Представление постоянного поколения
  • Tomcat Wiki: как справиться с ошибками памяти

Проблема в общих чертах – это модель безопасности Java, которая на самом деле пытается предотвратить перезагрузку уже загруженного classа.

Конечно, Java с самого начала поддерживала динамическую загрузку classов, что сложно – это перезагрузка classа.

Было сочтено вредным (и по уважительной причине), что запущенное приложение java было введено новым classом с вредоносным кодом. Например, java.lang.String взломал реализацию, исходящую из Интернета, вместо того, чтобы создавать строку, удаляет некоторый случайный файл hile, вызывающий метод length ().

Итак, они задумали Java, и я предполагаю, что .NET CLR в результате, потому что он был очень «вдохновлен» в JVM) заключался в том, чтобы предотвратить загрузку уже загруженного classа снова той же виртуальной машины.

Они предложили механизм для переопределения этой «функции». Classloaders, но опять же правила для загрузчиков classов были, они должны спросить разрешение «родительского» загрузчика classов перед попыткой загрузить новый class, если родитель уже загрузил class, новый class игнорируется.

Например, я использовал загрузчики classов, которые загружают classы из LDAP или RDBMS

Горячее развертывание становится необходимостью в мире Java, когда сервер приложений становится основным для Java EE (а также создает потребность в микроконтейнерах, таких как весна, чтобы избежать такого рода бремени).

Перезапуск всего сервера приложений после каждого компилятора приводит к тому, что любой сумасшедший.

Таким образом, поставщик приложений, предлагающий этот «пользовательский» загрузчик classов для быстрого развертывания и использования конфигурационного файла, это поведение, СЛЕДУЕТ быть отключенным при установке в процессе производства. Но компромисс заключается в том, что вы должны использовать тонны памяти в процессе разработки. Таким образом, хороший способ сделать это – перезапустить каждые 3 – 4 развертывания.

Это не происходит с другими языками, которые были разработаны с самого начала для загрузки их classов.

Например, в Ruby вы можете добавлять методы к запущенному classу, переопределять метод во время выполнения или даже добавлять один метод к уникальному определенному объекту.

Компромисс в таких средах – это, конечно, память и скорость.

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ

Я нашел этот продукт некоторое время назад, что обещает, что перезагрузка станет максимально простой. Я не помнил ссылку, когда я впервые написал этот ответ, и я это делаю.

Это JavaRebel от ZeroTurnaround

Sun JVM имеет фиксированное пространство PermGen, и в конечном итоге все это потребляется (да, по-видимому, из-за ошибки в коде, связанной с загрузкой classов) => OOM.

Если вы можете использовать JVM другого вендора (например, Weblogic one), он динамически расширяет пространство PermGen, поэтому вы никогда не получите OOM с привязкой к переносу.

Какую версию java вы используете? Были ошибки в раннем Sun 1.4.2, но он работает долгое время.
Кстати, как вы можете разделить новости с командой? Вы руководите командой?

  • ограничение отладки java ssl debug
  • Java - получить список всех classов, загруженных в JVM
  • Есть ли лучшее объяснение рамок карты стека?
  • Как получить нить и кучу дампа процесса Java в Windows, который не работает в консоли
  • Как написать правильный микро-тест в Java?
  • Как указать аргументы JVM по умолчанию для программ, которые я запускаю из eclipse?
  • Можно ли скомпилировать код Java 8 для работы на Java 7 JVM?
  • Зачем вам когда-либо реализовывать finalize ()?
  • Общая память между двумя JVM
  • Возможные причины Java VM EXCEPTION_ACCESS_VIOLATION?
  • Узнайте, что работает JVM Eclipse
  • Давайте будем гением компьютера.