SpringBoot недостаточно памяти для среды выполнения Java

#java #spring-boot #memory-leaks

Вопрос:

Я выполняю более 30000 запросов REST в 5 потоках (по 6000 на поток), чтобы запустить Swagger поверх Tomcat внутри SpringBoot и получить следующую ошибку после 35 минут работы:

 #
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 16384 bytes for committing reserved memory.
# Possible reasons:
#   The system is out of physical RAM or swap space
#   The process is running with CompressedOops enabled, and the Java Heap may be blocking the growth of the native heap
# Possible solutions:
#   Reduce memory load on the system
#   Increase physical memory or swap space
#   Check if swap backing store is full
#   Decrease Java heap size (-Xmx/-Xms)
#   Decrease number of Java threads
#   Decrease Java thread stack sizes (-Xss)
#   Set larger code cache with -XX:ReservedCodeCacheSize=
#   JVM is running with Zero Based Compressed Oops mode in which the Java heap is
#     placed in the first 32GB address space. The Java Heap base address is the
#     maximum limit for the native heap growth. Please use -XX:HeapBaseMinAddress
#     to set the Java Heap base and to place the Java Heap above 32GB virtual address.
# This output file may be truncated or incomplete.
#
#  Out of Memory Error (os_linux.cpp:2985), pid=24780, tid=58785
#
# JRE version: OpenJDK Runtime Environment (11.0.11 9) (build 11.0.11 9-Ubuntu-0ubuntu2.20.04)
# Java VM: OpenJDK 64-Bit Server VM (11.0.11 9-Ubuntu-0ubuntu2.20.04, mixed mode, sharing, tiered, compressed oops, g1 gc, linux-amd64)

Command Line: -Xverify:none -XX:TieredStopAtLevel=1 -Xms2g -Xmx10g com.CamelSpringBootApplication

Host: Common KVM processor, 16 cores, 28G, Ubuntu 20.04.2 LTS
Time: Mon May 31 15:40:22 2021 CEST elapsed time: 2122.252495 seconds (0d 0h 35m 22s)
 

Приложение SpringBoot работает на виртуальной машине Ubuntu, которая должна иметь 64 ГБ оперативной памяти, но значение падает как сумасшедшее, как вы можете видеть на следующем графике.

Мне не хватает некоторой информации, и я не знаю причины этого. Где я совершаю ошибку? Что именно занимает так много памяти и как я могу освободить память во время выполнения?

Память возвращается к 64 ГБ только после перезапуска виртуальной машины. После того, как я снова запускаю приложение SpringBoot, оперативная память начинает уменьшаться еще до выполнения остальных запросов. Мне нужно поддерживать как можно больше запросов на отдых, сохранять оперативную память и предотвращать сбой приложения SpringBoot.

введите описание изображения здесь

Обновить:

Это результаты собранного дампа кучи. Я загрузил heapdump.bin в heaphero.io. Я был бы признателен за любые советы, основанные на этих результатах.

введите описание изображения здесь

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

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

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

3. Смотрите это о том, как получить свалки кучи. Затем вы можете использовать такие инструменты, как анализатор памяти eclipse, для его анализа.

4. Я обновил вопрос статистикой сброса кучи. Я постараюсь очистить строки после использования.

5. Мне не удалось найти точную причину/причины такого поведения памяти, но очень вероятно, что основная причина этого кроется в моем коде, который следует отредактировать и оптимизировать. Другая возможная причина утечки памяти заключается в том, что Tomcat в Spring Boot должен обрабатывать довольно большое количество запросов (которые должны быть должным образом закрыты, если не выполняются автоматически) за короткое время и должны быть правильно настроены для этой задачи.

Ответ №1:

Просто рискну предположить, что вы, возможно, опережаете сбор мусора После подсчета четверти от числа этих 30000 или около того, вызовите System.gc ();, чтобы уведомить о сборе мусора. Это, что я написал, находится в оперативной памяти и требует небольшой проверки и счетчика управления мусором.

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

1. Я добавил довольно много вызовов System.gc() в код и перед ними установил переменные (в основном списки массивов, карты и объекты JSONObjects) в значение null, но похоже, что Java игнорирует эти вызовы, и память все еще сокращается.

Ответ №2:

Я надеюсь, что вы выделили достаточный размер кучи, даже если у вас есть 64 ГБ оперативной памяти для вашей машины Linux, вам необходимо внешне расширить ее емкость по умолчанию в соответствии с входящим трафиком приложений.

Вы можете увеличить размер кучи для приложения spring boot внутри pom.xml файл выглядит следующим образом —

 <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <jvmArguments>-Xmx4096m</jvmArguments>
    </configuration>
</plugin>
 

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

1. Я расширил Xmx до 16 ГБ, но это не помогло.