Подтвердить что ты не робот

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

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

Итак, провайдер сервера приложений, предлагайте этот "пользовательский" загрузчик классов, чтобы помочь в горячем развертывании и используя файл конфигурации, это поведение, ДОЛЖНО быть отключено при установке в процессе производства. Но компромисс заключается в том, что вы должны использовать тонны памяти в процессе разработки. Таким образом, хороший способ сделать это - перезапустить каждые 3 - 4 развертывания.

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

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

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

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

ИЗМЕНИТЬ

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

Это JavaRebel от ZeroTurnaround

Ответ 3

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

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

Ответ 4

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