У нас в течение некоторого времени наш экземпляр Glassfish отключается каждые две недели с java.lang.OutOfMemoryError: PermGen space
. Я увеличил пространство PermGen до 512 МБ и начал использовать сброс памяти с помощью jstat -gc
. Через две недели я придумал следующий график, который показывает, как пространство PermGen неуклонно увеличивается (единицы по оси x - минуты, ось y - КБ).
Я пробовал поискать в Google какой-то инструмент профилирования, который мог бы точно определить ошибку, и в ветке SO упоминался jmap, который оказался весьма полезным. Из примерно 14000 строк, сброшенных из jmap -permstats $ PID
, примерно 12500 содержат groovy / lang / GroovyClassLoader $ InnerLoader
, указывая на некоторую утечку памяти из нашего собственного кода Groovy. или сам Groovy. Я должен указать, что Groovy составляет менее 1% соответствующей кодовой базы.
Пример вывода ниже:
class_loader classes bytes parent_loader alive? type
3811 14830264 null live
0x00007f3aa7e19d20 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa7c850d0 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa5d15128 21 181072 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aad0b40e8 36 189816 0x00007f3a9d31fbf8 dead org/apache/jasper/servlet/JasperLoader@0x00007f3a7d0caf00
....
Итак, как мне продолжить, чтобы узнать больше о том, какой код вызывает это?
Из В этой статье Я сделал вывод, что наш код Groovy где-то динамически создает классы. И из дампа из jmap я вижу, что большинство мертвых объектов / классов (?) Имеют один и тот же parent_loader, хотя я не уверен, что это значит в данном контексте. Я не знаю, как действовать дальше.
Для опоздавших стоит отметить, что принятый ответ не решает проблему . Он просто увеличивает период, необходимый до перезагрузки, в десять раз, не сохраняя так много информации о классе. Что на самом деле решило наши проблемы, так это избавление от кода, который их генерировал. Мы использовали структуру проверки (проектирование по контракту) OVal , в которой можно было написать собственные ограничения, используя Groovy в качестве аннотаций для методов и классов. Удаление аннотаций в пользу явных предварительных и пост-условий в простой Java было скучным, но это сделало свою работу. Я подозреваю, что каждый раз, когда проверялось ограничение OVal, создавался новый анонимный класс, и каким-то образом связанные данные класса вызывали утечку памяти.