Алгоритмы, которые приводят к java.lang.OutOfMemoryError: ошибка пространства PermGen

Я получаю ошибку пространства PermGen на Sun JVM (1.6.0_21-b06) (Хорошо, это Oracle :)). Увеличение значения опции -XX:MaxPermGen не помогает. Я знаю, что PermGen — это пространство, предназначенное для постоянных объектов, таких как метаданные класса. Количество классов в проекте не такое уж большое ~ 10 000. Перед крахом jvisualvm показывает 57MB как Used PermGen.

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

UPD. Такой абстрактный вопрос задаю, потому что в данный момент не могу пользоваться никаким профилировщиком - код крашится настолько сильно, что jvisualvm и eclipse перестают реагировать. Мне нужно убить Java-процессы с терминала с помощью kill -KILL {process_numer}. Я работаю с плохо организованным (но коммерческим) кодом, который имеет много потоков и обмен сообщениями JMS. Отладка - это беспорядок - сначала мне нужно понять, где искать.


person Nulldevice    schedule 04.10.2010    source источник
comment
Уровень абстракции вашего вопроса убивает;). Используйте профилировщик Java (например, virtualvm), чтобы узнать, что приводит к сбою вашей программы. Если вы обнаружите проблему, пожалуйста, перепишите свой вопрос.   -  person Skarab    schedule 04.10.2010
comment
Просто из любопытства, можете ли вы показать точные параметры командной строки, которые вы используете?   -  person karoberts    schedule 04.10.2010
comment
Чего бы вы добились, зная примеры кода, приводящего к переполнению PermGen? Вы пытаетесь восхищаться проблемой, а затем создаете проблемы из восхищения, или вы пытаетесь ее решить? Я много раз видел, как этот метод решения проблем терпит неудачу, лучше искать основную причину и устранять ее. Как и Скараб, предложил использовать профилировщик Java. Понятно, если вы исследователь или студент, но не похоже.   -  person sjt    schedule 04.10.2010
comment
@Nulldevice Я вижу, вы заметили обмен сообщениями jms. У меня была аналогичная проблема, связанная с JMS, проверьте, закрыты ли ваши соединения jms. Проверьте мой ответ ниже, в нем есть более подробная информация.   -  person sjt    schedule 04.10.2010
comment
Чтобы дать более конструктивный отзыв, попробуйте eclipse.org/proposals/memory-analyzer. Это анализатор дампа памяти Java. Это очень полезно после неожиданной ошибки.   -  person Skarab    schedule 04.10.2010
comment
Количество классов кажется небольшим. Другой способ получить это исключение — использовать String.intern(). Не могли бы вы опубликовать код?   -  person Jayan    schedule 04.10.2010


Ответы (6)


Кто-нибудь знает примеры алгоритмов, приводящих к переполнению PermGen?

Да, но какой в ​​этом смысл? если вы хотите исправить это, установите инструмент профилирования памяти, такой как jprobe или лямбда-зонд, и проверьте, где происходит утечка памяти, и исправьте это. Теперь для примера: есть тысячи способов превзойти перманентное пространство. Я заметил в проекте, когда мы унаследовали приложение, в котором они использовали JMS. Соединения jms были оставлены открытыми, приложение рухнуло через несколько минут после того, как оно получило много запросов с такой же ошибкой, как и вы. Обратите внимание: когда мы перешли на weblogic с jboss (перешли на beajrockit), он удивительным образом исправился или, по крайней мере, принял на себя удар технического долга. Мой совет, независимо от этого, сначала следует исправить плохой код с утечками памяти, а затем возиться с серверами приложений и параметрами распределения пространства в куче.

Вот полезная ссылка с некоторой информацией об исключении, которое вы получаете. http://www.jroller.com/agileanswers/entry/preventing_java_s_java_lang

ИЗМЕНИТЬ

Эта ссылка может быть полезна http://www.precisejava.com/javaperf/j2ee/JMS.htm

person sjt    schedule 04.10.2010
comment
Я думаю, что в моем случае ваша идея о JMS наиболее перспективна. Некоторые сообщения отправляются непосредственно перед сбоем. - person Nulldevice; 04.10.2010
comment
Особенность JMS-фреймворка в том, что он асинхронный, может быть получено несколько асинхронных запросов, когда jms-соединение не закрыто, это может привести к проблемам. Удачи. - person sjt; 04.10.2010

Дело не столько в алгоритме, сколько в реализации. Вот действительно глупый способ генерировать случайные строки, которые заполняют пространство PermGen:

    Random rnd = new Random();
    List<String> interned = new ArrayList<String>();
    for (;;) {
        int length = rnd.nextInt(100);
        StringBuilder builder = new StringBuilder();
        String chars = "abcdefghijklmnopqrstuvwxyz";
        for ( int i = 0; i < length; i++ ) {
            builder.append(chars.charAt(rnd.nextInt(chars.length())));
        }
        interned.add(builder.toString().intern());
    }

Вкратце: интернирование строк — это то, что может съесть память PermGen.

person Mark Peters    schedule 04.10.2010

Есть две вещи, которые могут привести к проблемам с пространством PermGen:

  1. Метод String.intern(String) создает строки в куче PermGen. Если вы много интернируете и прямо (или косвенно) сохраняете ссылки на интернированные строки, вы можете заполнить PermGen.

  2. Загрузчики классов создают внутренние дескрипторы классов JVM и сегменты кода в куче PermGen. Если ваше приложение выполняет большую динамическую загрузку классов, а объекты класса не удаляются сборщиком мусора, вы можете заполнить PermGen.

Горячее повторное развертывание веб-приложений Java основано на динамической загрузке и является распространенным источником проблем PermGen. Основной причиной обычно является утечка памяти, связанная со скрытой ссылкой какого-либо объекта на старый загрузчик классов. (Tomcat часто получает за это "палку", но реальная проблема обычно заключается в перераспределяемом веб-приложении.)

Насколько мне известно, случай с прокси, упомянутый @Michael Borgwardt, также является результатом того, что реализация Proxy генерирует файлы классов и загружает их на лету.

person Stephen C    schedule 04.10.2010

Если вы используете java.lang.reflect.Proxy очень интенсивно, что также может занять место в PermGen.

person Michael Borgwardt    schedule 04.10.2010

Проверьте анализатор памяти — http://www.eclipse.org/mat/. Это анализатор дампа памяти Java. Это очень полезно после неожиданной ошибки.

person Skarab    schedule 04.10.2010

Вы используете другой сборщик мусора?

Сборщик пропускной способности выдаст исключение нехватки памяти, если на сборку мусора тратится слишком много времени. Например, если JVM тратит более 98 % общего времени на сборку мусора и восстанавливает менее 2 % кучи, это вызовет ожидание нехватки памяти. Реализация этой функции изменилась в версии 1.5. Политика та же, но могут быть небольшие отличия в поведении из-за новой реализации». «В версии 1.5 платформы J2SE сборщик пропускной способности будет выбран в качестве сборщика мусора на машинах серверного класса». http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html

Ознакомьтесь с некоторыми инструкциями на этом< /а> страница.

person Denis Tulskiy    schedule 04.10.2010