Превышен лимит накладных расходов GC, но осталась память

#java #garbage-collection

#java #сбор мусора

Вопрос:

Я получил

 java.lang.OutOfMemoryError: GC overhead limit exceeded
  

при разделении некоторых строк. Интересно, что ни память не была израсходована, ни сборщик мусора не сходил с ума: Вывод JVisualVM

Исключение появилось в 11:10, когда Eclipse заморозил программу перед фактическим выбросом исключения. Так что все после 11:10 может быть просто шумом.

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

Комментарии:

1. Вы пробовали запускать, -XX: HeapDumpOnOutOfMemoryError а затем проверять дамп?

2. У меня есть дамп, но на самом деле я не знаю, что искать.

3. Хм … например, необычно большое количество экземпляров объектов для класса, где вы этого не ожидаете. Но есть кое-что еще, что вы можете сделать: поместить исключение OutOfMemoryError . Теперь, когда происходит ООМ, у вас есть не только соответствующая трассировка стека, но и фактическое использование отладчика для проверки входных параметров и т. Д. В момент сбоя.

4. У вас есть объяснение количества потоков, взрывающихся примерно в 10: 12?

5. Нет. Это либо какой-то артефакт JVisualVM-Eclipse-Connection после исключения, либо что-то неизвестное. Но это определенно произошло после того, как исключение было замечено Eclipse.

Ответ №1:

Вы используете сборку с остановкой мира (возможно, параллельная очистка).Это исключение связано с тем, что GC занимает слишком много времени, что может составлять более 98% от общего времени выполнения. В этом случае JVM завершает процесс, поскольку никакой реальной работы не выполняется.

Решения могут быть:

  1. Попробуйте другой тип GC, например, одновременную развертку по меткам, которая не является GC с остановкой мира;
  2. Попробуйте увеличить объем памяти, чтобы GC выполнялся не так часто;
  3. Игнорируйте это ограничение времени GC с помощью using -XX:-UseGCOverheadLimit , что может вызвать проблемы, поскольку JVM продолжает работать над GC вместо реальной работы;
  4. Как уже упоминалось, выполните сброс трассировки памяти с -XX: HeapDumpOnOutOfMemoryError помощью и проанализируйте трассировку.

Немного больше объяснений, почему куча не заполнена, но GC превышает лимит (все это предположения, и для проверки причин требуется больше трассировок): это может быть

  1. слишком маленькое молодое поколение или большинство объектов выживают после незначительного GC, поэтому GC происходит слишком часто и / или тратит много времени на перемещение объектов (это может быть настроено путем изменения размера молодого поколения в куче или изменения скорости владения объектами с помощью некоторого флага JVM);
  2. слишком маленький размер старого поколения, который объекты сохранили из второстепенного GC, не может быть помещен в старое поколение, что приводит к частому большому GC (или полному GC кучи).