Поиск кода, который заполняет PermGen мертвым кодом Groovy - PullRequest
10 голосов
/ 28 апреля 2011

У нашего экземпляра стеклянной рыбы какое-то время выходили из строя каждые две недели с java.lang.OutOfMemoryError: PermGen space.Я увеличил пространство PermGen до 512 МБ и начал использовать дамп памяти с jstat -gc.Через две недели я придумал следующий график, который показывает, как пространство PermGen неуклонно увеличивается (единицы по оси x - минуты, по оси y - КБ).Graph of increasing PermGen usage

Я попытался поискать какой-нибудь инструмент для профилирования, который мог бы точно определить ошибку и поток здесь, на упомянутом выше 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/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
....

Итак, как я могу узнать больше о том, какой код вызываетthis?

Из этой статьи Я делаю вывод, что наш Groovy-код динамически создает классы где-то.И из дампа из jmap я вижу, что большинство мертвых объектов / классов (?) Имеют одинаковый parent_loader, хотя я не уверен, что это означает в этом контексте.Я не знаю, как действовать дальше.

Приложение

Для опоздавших стоит отметить, что принятый ответ не решает проблему .Он просто продлевает период, необходимый для перезагрузки, в десять раз, не сохраняя так много информации о классе.Что действительно исправило наши проблемы, так это избавление от кода, который его сгенерировал.Мы использовали платформу валидации (Design by contract) OVal , где можно было писать скрипты пользовательских ограничений, используя Groovy в качестве аннотаций для методов и классов.Удаление аннотаций в пользу явных предварительных и постусловий в простой Java было скучным, но это сделало свою работу.Я подозреваю, что каждый раз при проверке ограничения OVal создавался новый анонимный класс, и каким-то образом данные связанного класса вызывали утечку памяти.

Ответы [ 2 ]

3 голосов
/ 07 мая 2012

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

GroovyClassLoader loader = new GroovyClassLoader();
Reader reader = new BufferedReader(clob.getCharacterStream());
GroovyCodeSource source = new GroovyCodeSource(reader, name, "xb3.Classifier");
Class<?> groovyClass = loader.parseClass(source);
Object possibleClass = groovyClass.newInstance();
if (expectedType.isAssignableFrom(possibleClass.getClass())) {
    classifiers.put((T) possibleClass, name);
}
reader.close();
// Tell Groovy we don't need any meta
// information about these classes
GroovySystem.getMetaClassRegistry().removeMetaClass(possibleClass.getClass());
// Tell the loader to clear out it's cache,
// this ensures the classes will be GC'd
loader.clearCache();
0 голосов
/ 18 мая 2011

Если вы используете Sun JVM, измените его на IBM JVM, он будет работать нормально, я надеюсь:)

...