Страницы

Поиск по вопросам

четверг, 19 декабря 2019 г.

OutOfMemoryError: GC overhead limit exceeded при параметрах -Xmx8192M -XX:-UseGCOverheadLimit

#java #junit #jvm #сборщик_мусора


jUnit тесты работают с большими объемами данных, в частности, данная ошибка возникает,
когда считываем данные из базы в объект.

ОЗУ - 16 Гб, 4 виртуальных процессора

когда возникла ошибка

java.lang.OutOfMemoryError: GC overhead limit exceeded
at sun.reflect.GeneratedConstructorAccessor47.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at java.lang.Class.newInstance(Class.java:442)


то я добавил параметр -XX:-UseGCOverheadLimit
но получил следующую ошибку:

java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.lang.reflect.Field.copy(Field.java:150)
    at java.lang.reflect.ReflectAccess.copyField(ReflectAccess.java:144)
    at sun.reflect.ReflectionFactory.copyField(ReflectionFactory.java:309)
    at java.lang.Class.copyFields(Class.java:3115)
    at java.lang.Class.getFields(Class.java:1557)
    at main.java.DataFormat.DbTable.loadObjectFromResultSet(DbTable.java:101)
    at main.java.DataFormat.DbTable.getEntities(DbTable.java:57)


все параметры JVM -Xmx8192M -XX:-UseGCOverheadLimit

в момент появления ошибки были следующие параметры системы: 
ОЗУ стабильно на 46% (7400Мб), ЦПУ 77%-82% (82% в момент появления ошибки) 

подскажите, как исправить данную проблему? 

Спарвка


  
  java.lang.OutOfMemoryError: GC overhead limit exceeded
  
  
  Данная ошибка может возникнуть как при переполнении первой, так и
  второй областей. Связана она с тем, что памяти осталось мало и GC
  постоянно работает, пытаясь высвободить немного места. Данную ошибку
  можно отключить с помощью параметра -XX:-UseGCOverheadLimit, но,
  конечно же, её надо не отключать, а либо решать проблему утечки
  памяти, либо выделять больше объема, либо менять настройки GC.


Ответ
String объект слишком много весит. а у меня там очень много стрингов. Для примера,
посчитали файл, который весит 250 МБ, имеет 1600 символов в строке и 220 000 строк.
Заполняю в ArrayList lines, где каждая строка записана как объект из 250 полей,
которые принимают значение из 1600 символов. Такой объект весил чуть больше 6Гб. 

Решение: увеличил память до 14Гб. теперь проблема в том, что 6Гбайтный объект не
помещается в куче, надо думать что-то другое и пожертвовать временем выполнения теста. 
    


Ответы

Ответ 1



В данном случае ошибка java.lang.OutOfMemoryError: GC overhead limit exceeded говорит о том, что Вы пытаетесь обработать такой объем данных который не помещается в память. В приведенной Вами справке упомянуто, что ошибка выбрасывается, когда область памяти, занимаемая только, что созданными объектами переполняется. Плюс к этому в трассировке стека видно, что ваши классы ( at main.java.DataFormat.DbTable.loadObjectFromResultSet(DbTable.java:101) at main.java.DataFormat.DbTable.getEntities(DbTable.java:57) ) в момент получения ошибки как раз пытаются выгрузить данные из базы. Поэтому простой и неутешительный вывод из вышесказанного тестируйте на меньшем объеме данных или выделяйте больший объем под выгружаем данные(-Xmx12000M) если они туда поместятся, то ошибка исчезнет. Настраивать сборку мусора в данном случае бесполезно т.к. GC не сможет удалить загружаемые объекты потому как они еще используются.

Ответ 2



Начту с основ для лучшего понимания ошибки. JVM имеет две области памяти: Heap Memory и Non-Heap Memory. Heap Memory - хранит объекты; Non-Heap Memory - хранит параметры методов, примитивные типы и т.д. В Вашем случае происходит переполнение Heap Memory, т.к. очень много создается объектов, которые не вмещаются в Heap Memory. Решить проблему можно увеличив Heap Memory (ключ -Xmx), что не всегда помогает, т.к. объем данных может быть больше чем доступно ОЗУ, поэтому лучше реализовать обработку данных из БД порционно, т.е. выгружать часть данных, чтобы объекты поместились в памяти, затем убивать их (присваивать null, чтобы GC разгрузить), замет следующею часть и т.д. P.S. Стоит понимать, что Heap не равно ОЗУ. Heap - это только зарезервированная память для JVM, больше данного резерва JVM использовать не может даже, если ОЗУ в избытке.

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

Отправить комментарий