Запрос Java, занимающий 40-50 МБ памяти (Spring JPA Hibernate)

Я использую весеннюю загрузку с JPA Hibernate. Я слежу за службой Heap и обнаружил, что каждый мой запрос занимает около 40-50 МБ.

Таким образом, объем памяти увеличивается, после нескольких запусков GC он освобождает память, и это продолжается бесконечно.

Итак, мой первый вопрос: это утечка памяти?

Также я пытаюсь найти причину этого. Итак, я использовал Runtime.getRuntime () freeMemory и totalMemory (), чтобы определить, что около 15 МБ используется при получении одного вызова БД и заполнении им проекции.

public interface RecommendationProjection {
    public String getType();
    public boolean getIsOK();
    public int getId();
    public int getTagCount();
    public double getQuality() ;
    public LocalDateTime getLastActivity();

}

а спящий режим возвращает 567 записей, поэтому в основном то, что я получаю из БД, - это список 567 выше проекции. Но чего я не понимаю, как этот объект может занимать такую ​​большую память? Причина этого - спящий режим?

При использовании проекции, спящий режим запрашивает конкретное поле или извлекает все поля из базы данных?

Затем я сопоставляю этот домен с DTO, который снова использует 15-20 МБ памяти? это мой DTO

public class RecommendationInfoDTO {
    private String type;
    private boolean isOK;
    private int id;
    private int tagCount;
    private double quality ;
    @JsonFormat(shape=JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "IST")
    private LocalDateTime lastActivity;


    .. getters and setters
}

К вашему сведению: для мониторинга я использую VisualVM. Кто-нибудь может сказать мне, в чем может быть проблема?

Я также проанализировал дамп кучи, но ничего не нашел?

Запрос Java, занимающий 40-50 МБ памяти (Spring JPA Hibernate)

Это моя разница в дампе кучи.

Я запускаю 6 запросов гибернации в запросе и 3 простых простых запроса mysql (с использованием вызова jdbc)

Проблема только в 1 вызове гибернации. Я думаю, что с моим режимом гибернации что-то не так? Есть ли способ выполнить профилирование на основе запросов?

Gc / График памяти

Запрос Java, занимающий 40-50 МБ памяти (Spring JPA Hibernate)

Дамп кучи, отсортированный по размеру

Запрос Java, занимающий 40-50 МБ памяти (Spring JPA Hibernate)

Какую версию Java вы используете?

dgebert 02.04.2018 11:32

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

hovanessyan 02.04.2018 11:33

Можете ли вы показать дамп кучи, отсортированный по последнему столбцу, то есть по размеру?

Madhusudana Reddy Sunnapu 02.04.2018 11:39

Какой минимальный и максимальный размер кучи вы используете? Как долго вы запускаете свое приложение и сколько запросов отправили вашему приложению? У вас есть ошибки OOM? И можете ли вы также показать вам график GC.

Madhusudana Reddy Sunnapu 02.04.2018 12:08

Я использую Java 8, я уже видел, что проекция запроса работает нормально. Запрос получает только определенные записи. Минимальная куча 512 МБ и максимальная куча 1024 МБ. Тестирую на локальном. Такой одиночный (без одновременного запроса с использованием 40 МБ)

Ankit Bansal 02.04.2018 13:21

Можете ли вы запустить запрос пару раз и поделиться своими наблюдениями за памятью кучи. Вы можете проигнорировать начальные один / два прогона и рассмотреть последующие для этого наблюдения. И поделитесь своим графиком GC из visualVM.

Madhusudana Reddy Sunnapu 02.04.2018 13:58

Да так же даже через 10 раз. Потребляет 40 МБ на запрос

Ankit Bansal 02.04.2018 13:59

Хорошо ... хотелось бы увидеть ваш график GC из visualVM и количество экземпляров вышеуказанного класса, которое отсортировано на основе последнего столбца, то есть размера.

Madhusudana Reddy Sunnapu 02.04.2018 14:02

обновил вопрос. Пожалуйста, посмотрите

Ankit Bansal 02.04.2018 14:11

Это похоже на чрезмерно большое количество экземпляров внутреннего класса ConnectionPropertiesImpl, учитывая количество подключений к базе данных. Похоже, проблема в драйвере SQL. Попробуйте драйвер MariaDB (ответвление MySQL, драйвер совместим) github.com/MariaDB/mariadb-connector-j и сообщите нам, имеет ли это значение.

coladict 02.04.2018 15:15

На этом вопрос нужно закрыть. Это уже проскочило как вопрос с несколькими вопросами. Q1: «Это утечка памяти» A: «Нет, по определению» Q2: «Я неправильно использую спящий режим / это ошибка» и т. д. A: «Мы не можем знать, что, не увидев вашего кода» Q3: «Запросы спящего режима для конкретное поле или извлекает все поля из базы данных? " A: «Конкретный» Вопрос 2 нужно открыть как новый вопрос отдельно.

Stephan 09.04.2018 17:01

Я все еще не получил ответа

Ankit Bansal 09.04.2018 17:26
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
10
12
1 776
2

Ответы 2

Ниже мой взгляд:

So the memory gets increased, after few requests GC runs, it frees the memory and this goes on forever.

So my first question is that is this memory leak?

Не обязательно утечка памяти. Но вам нужно запускать и запускать приложение в течение более длительного периода времени и смотреть, как освобождается память во время циклов сборки мусора. Пока использование памяти как бы следует пилообразному образцу является индикатором того, что сборщик мусора может удалить мусор и память используется эффективно.

When using projection, hibernate queries for specific field or fetches all fields from database?

Нет, в случае проецирования выбираются только указанные столбцы.

Then I am mapping this domain to DTO, which again uses 15-20MB memory?

Это не только ваши DTO, но hibernate и поверх spring-data-jpa будут создавать свои собственные объекты внутри для выполнения запроса, и эти объекты могут ожидать GC. Если они восстанавливаются после цикла сборки мусора, а использование памяти не увеличивается постоянно после каждого сборщика мусора, это хороший признак.

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

  1. Посмотрите, как используется память в течение определенного периода времени для сценариев нормальной и пиковой нагрузки.
  2. Как часто происходят второстепенные и крупные сборщики мусора и как это влияет на приложение?
  3. Приложение тратит слишком много времени на сборку мусора "?
  4. Настройте сборщик мусора в зависимости от поведения приложения. Например: приложение создает слишком много недолговечных объектов для обслуживания запросов и т. д.
  5. С учетом конфигурации кучи / сборщика мусора, сможет ли приложение обеспечить ожидаемое время отклика и пропускную способность вашего приложения?

И, наконец, вы можете пройти Руководство по настройке java8 GC, чтобы понять GC и настроить его.

Мне это кажется нормальным поведением.

So my first question is that is this memory leak?

Нет. Утечки памяти требуют, чтобы память оставалась выделенной по истечении срока ее полезного использования. Поскольку ваш GC очищает общее пространство памяти, потребляемое запросом, утечка не происходит, вы просто используете память.

But what i dont understand that how could this object take such high memory?

Объект не занимает много памяти, память занимает 567 экземпляры объекта на запрос.

Давайте посмотрим, почему:

Каждый экземпляр вашей проекции содержит

  • String неизвестной длины (строки не являются примитивами, поэтому существует значительное количество атрибутов метаданных на одной вершине чистого количества символов, но позволяет просто сказать 1 байт)
  • boolean, который выделяет 1 байт
  • 2 int байта каждый
  • double из 2 байтов
  • и LocalDateTime, который состоит из нескольких полей (так что давайте будем оптимистичны и скажем, что это 2 байта)

Таким образом, каждый экземпляр имеет размер по меньшей мере 8 байтов. 567 * 8 = минимум 4536 байт на запрос.

Вы запускаете 6 запросов к этому набору данных 4536 * 6 = 27216 байт на вызов метода

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

Это относительно близко к тому, что вы наблюдаете, поэтому я не думаю, что что-то не так.

Если вы ожидаете меньшей занимаемой площади, пересмотрите свой подход, чтобы повторно использовать как можно больше данных, чтобы уменьшить количество запросов, которые вам нужно сделать.

Я использую всего 6 запросов. Но выполняется только запрос, который извлекает 567 строк. Остальные запросы - это простые запросы, которые не занимают много памяти, поскольку я удалил все остальные, и все еще используется почти такая же память. Таким образом, это всего лишь один запрос, который дает 567 строк. Я использую проекцию для получения 6 определенных столбцов? Так будет ли в этом случае спящий режим использовать кеш первого уровня? Если да, то что кеширует. Единственная проблема, которую я чувствую, заключается в том, что jpa данных hibernate / spring делает что-то за кулисами. Мой запрос - это запрос на соединение с объединением 3 таблиц и выборкой 6 столбцов с использованием проекции

Ankit Bansal 05.04.2018 21:10

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

Stephan 09.04.2018 17:09

Другие вопросы по теме