2013-10-24 3 views
5

Я пытаюсь создать классы и загрузить их во время выполнения.
Я использую объект ClassLoader для загрузки классов. Поскольку я не хочу выходить из памяти PermGen, время от времени я не ссылаюсь на загрузчик классов и создаю новую для загрузки новых классов, которые будут использоваться. Кажется, это работает нормально, и я не получаю из памяти PermGen. Проблемы заключается в том, что, когда я делаю это, через некоторое время я получаю следующее сообщение об ошибке:Избежание превышения PermGen и превышения верхнего предела GC

java.lang.OutOfMemoryError: GC overhead limit exceeded 

Так что мой вопрос, когда я должен ООН ССЫЛКИ загрузчик классов, чтобы избежать оба ошибок ?:
Должен ли я мониторинг в моем коде используется PermGen, чтобы я не ссылался на загрузчик классов и вызывал System.gc(), когда использование PermGen близко к пределу?
Или мне следует придерживаться другого подхода?
Спасибо

ответ

6

На это нет ни одного правильного ответа.

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

С другой стороны, ошибка «превышение верхнего предела GC» означает, что ваше приложение тратит слишком много времени на сбор мусора. В большинстве случаев это означает, что ваша куча слишком заполнена. Но это может означать одну из двух вещей:

  • Куча слишком мала для требований вашего приложения.

  • Ваше приложение имеет утечку памяти.

Вы можете предположить, что проблема в том, что проблема была прежняя, и просто увеличить размер кучи. Но если реальная проблема - последняя, ​​то увеличение размера кучи просто откладывает неизбежное ... и правильно вещь, чтобы сделать было бы найти и исправить утечки памяти.


Не звоните System.gc(). Это не поможет.

+0

Я использую jvisualvm для мониторинга использования кучи, максимальный размер составляет 1 Гб, а использование варьируется от 200 мб до 600 мб, поэтому оно далека от предела. – otonakav

+0

@otonakav - возможно, есть некоторые проблемы с параметрами настройки GC. –

1

Вы загружаете один и тот же класс несколько раз? Потому что вы должны кэшировать загруженный класс.

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

+0

Вероятно, ограничение ограничит количество раз, когда я не ссылаюсь на загрузчик классов, так что GC не запускается слишком много раз, но я предполагал, что GC не будет работать, если будет много кучи и только PermGen потому что я не ссылаюсь на загрузчик классов, особенно если он будет пропускать верхний предел. – otonakav

+0

Я пытался указать, что проблема может заключаться в использовании загрузчика классов, а не за загрузчиком класса. –

1

У меня была похожая ситуация с разгрузкой классов.

Я использую несколько загрузчиков классов для моделирования нескольких JVM внутри теста JUnit (обычно это используется для работы с кластером Oracle Coherence, но я также успешно использовал этот метод для запуска кластера HBase/Hadoop с несколькими узлами внутри JVM).

Для различных целей испытаниям может потребоваться перезагрузка такой «виртуальной» JVM, что означает лишение старого ClassLoader и создание нового.

Иногда JVM задерживает событие разгрузки класса, если вы используете Full GC, что приводит к различным проблемам позже.

Один из методов, который я нашел полезным для принудительной сборки JVM для PermSpace.

public static void forcePermSpaceGC(double factor) { 
    if (PERM_SPACE_MBEAN == null) { 
     // probably not a HotSpot JVM 
     return; 
    } 
    else { 
     double f = ((double)getPermSpaceUsage())/getPermSpaceLimit(); 
     if (f > factor) { 

      List<String> bloat = new ArrayList<String>(); 
      int spree = 0; 
      int n = 0; 
      while(spree < 5) { 
       try { 
        byte[] b = new byte[1 << 20]; 
        Arrays.fill(b, (byte)('A' + ++n)); 
        bloat.add(new String(b).intern()); 
        spree = 0; 
       } 
       catch(OutOfMemoryError e) { 
        ++spree; 
        System.gc(); 
       } 
      } 
      return; 
     } 
    } 
} 

Full sourcecode

я заполняю PermSpace с String, не используя intern() до JVM будет собирать их.

Но

  • Я использую эту технику для тестирования
  • Различных комбинаций аппаратного/JVM версии может потребоваться различный порог, поэтому часто бывает быстрее, чтобы перезапустить всю JVM вместо того, чтобы заставить его правильно собирать весь мусор
Смежные вопросы