Память кучи Java, содержащая большой байтовый массив - PullRequest
5 голосов
/ 16 октября 2019

Мы используем Java 8 Spring Boot 2 для нашего приложения для микро-сервисов. Выполнение нагрузочного теста локально обнаружило, что память использует кучу, но никогда не освобождается обратно. Я запускаю приложение с сборщиком мусора G1, а также выполнил ручной сборщик мусора из JVisualVM, но выделенная память так и не освобождается.

Я взял дамп кучи и проанализировал его, и я ясно вижу большой байтмассив, созданный System Class Loader, указан как подозреваемый на утечку. Я вижу, что экземпляр байтового массива содержит мой HTTP-запрос к конечной точке "/ test". Но нагрузочный тест уже завершен, и потоки вернулись туда, где были до запуска нагрузочного теста.

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

JVisualVM

Подозреваемые утечки

байтовый массив

Объектыс исходящей ссылкой

/ конечная точка теста является единственным методом в классе @RestController

@RequestMapping(value = "/test", method = RequestMethod.GET)
@CrossOrigin(origins = "*")
public void test() {
    logger.info("Testing1...");
}

Ниже приведены приложения Spring Boot.properties, связанные с сервером:

server.port=8090
server.tomcat.max-threads=200
server.tomcat.accept-count=100
server.tomcat.min-spare-threads=20
server.error.whitelabel.enabled=false
server.max-http-header-size=2097152

Ответы [ 2 ]

6 голосов
/ 17 октября 2019

Tomcat кэширует несколько объектов, чтобы ускорить его работу. С параметром server.max-http-header-size=2097152 вы заставили один из этих кэшированных объектов потребовать 2 МБ памяти и сохранить его. В этом случае это Http11OutputBuffer, и вы можете увидеть здесь , что он требует (в вашем случае) 2 МБ памяти. Http11OutputBuffer используется Http11Processor, который вы можете увидеть здесь .

Документация содержит следующее, что можно сказать о processorCache:

Обработчик протокола кэширует объекты процессора для повышения производительности. Этот параметр определяет, сколько из этих объектов кэшируется. -1 означает неограниченный, по умолчанию 200. Если не используется асинхронная обработка Servlet 3.0, хорошим значением по умолчанию является использование параметра maxThreads. Если используется асинхронная обработка Servlet 3.0, по умолчанию рекомендуется использовать большее из maxThreads и максимальное количество ожидаемых одновременных запросов (синхронных и асинхронных).

Поэтому я предлагаю установить server.max-http-header-sizeк чему-то более разумному, например, 8 КБ (по умолчанию) и медленно удваивая это при тестировании, которое вам действительно нужно ( related : Tomcat выдает «400 Bad request», когда общий размер заголовка превышает server.max-http-header-size).

2 голосов
/ 16 октября 2019

Получите дамп до запуска стресс-теста и дамп после его запуска. Eclipse MAT позволяет сравнивать гистограмму между двумя дампами, чтобы вы знали, что произошла утечка памяти.

Я рекомендую использовать Java Mission Control (JMC) для мониторинга JVM, где вы можете подробнее рассмотретьпотребление памяти (куча, а не куча). Обратите внимание на разницу между используемой памятью и выделенной памятью.

В более новых версиях Java есть более сложные алгоритмы, в которых JVM возвращает память в ОС. Для Java 8 одним из вариантов является использование Eclipse Open J9 JVM.

Рекомендуемое чтение:

https://openjdk.java.net/jeps/346

https://jelastic.com/blog/elastic-jvm-vertical-scaling/

...