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