Память потрачена впустую приложением весенней загрузки

Одним из широко растрачиваемых ресурсов в современном мире является: Память. Из-за неэффективного программирования тратится удивительное (иногда «шокирующее») количество памяти. Мы видим, что этот шаблон повторяется в нескольких корпоративных приложениях. Чтобы доказать это, мы провели небольшое исследование. Мы проанализировали известное приложение Spring Boot Pet Clinic, чтобы увидеть, сколько памяти оно тратит впустую. Это приложение было разработано сообществом, чтобы показать, как можно использовать структуру приложений Spring для создания простых, но мощных приложений, ориентированных на базы данных.

Окружающая среда
Spring Boot 2.1.4.РЕЛИЗ
Java SDK 1.8
Томкэт 8.5.20
MySQL 5.7.26 с MySQL Connector/J 8.0.15

Стресс тест
Мы использовали Apache JMeter, популярный инструмент нагрузочного тестирования с открытым исходным кодом, для проведения нашего стресс-теста. Мы выполнили нагрузочный тест в течение 30 минут со следующими настройками:

Количество потоков (пользователей) – 1000 (Количество пользователей, подключающихся к цели)
Период разгона (в секундах) – 10. Сроки начала всех запросов. Согласно нашей конфигурации каждые 0,01 секунды будет запускаться 1 новый поток, т.е. 100 потоков в секунду.
Количество циклов – Навсегда. Эти 1000 потоков последовательно выполняют тестовые итерации.
Продолжительность (секунд) -1800. После запуска 1000 потоков непрерывно выполняются в течение 1800 секунд.
Захват.PNG
Рис: настройки Jmeter

В нашем нагрузочном тесте мы проверяли следующие сценарии:

*Добавить в систему нового владельца питомца.
* Просмотр информации о владельце домашнего животного.
* Добавить нового питомца в систему.
* Просмотр информации, касающейся домашнего животного.
* Добавить информацию о посещении в историю посещений питомца.
* Обновите информацию о домашнем животном.
* Обновите информацию о владельце домашнего животного.
* Просмотр информации о владельце путем поиска его имени.
* Просмотр информации обо всех владельцах.

Как измерить потерю памяти?
В отрасли есть сотни инструментов для отображения объема используемой памяти. Но редко мы сталкиваемся с инструментами, которые могут измерить количество памяти, потраченной впустую из-за неэффективного программирования. HeapHero — это простой инструмент, который анализирует ваши дампы кучи и сообщает, сколько памяти тратится впустую из-за неэффективного программирования.

Мы захватили дамп кучи из приложения Spring Boot Pet Clinic во время выполнения теста. (Существуют 7 различных вариантов захвата дампа кучи из приложений Java/Android. Вы можете выбрать тот вариант, который вам удобен).

Мы загрузили захваченный дамп кучи в инструмент HeapHero. Инструмент сгенерировал этот прекрасный отчет, показывающий, что 65% памяти тратится впустую из-за неэффективного программирования. Да, это простое ванильное приложение, в котором должны быть реализованы все лучшие практики, и это тоже на широко известном фреймворке тратит впустую 65% памяти.

В отрасли есть сотни инструментов для отображения объема используемой памяти. Но редко мы сталкиваемся с инструментами, которые могут измерить количество памяти, потраченной впустую из-за неэффективного программирования. HeapHero — это простой инструмент, который анализирует ваши дампы кучи и сообщает, сколько памяти тратится впустую из-за неэффективного программирования.

Мы захватили дамп кучи из приложения Spring Boot Pet Clinic во время выполнения теста. (есть 7 различных вариантов захвата дампа кучи из приложений Java/Android. Вы можете выбрать тот вариант, который вам удобен).

Мы загрузили захваченный дамп кучи в инструмент HeapHero. Инструмент сгенерировал этот прекрасный отчет, показывающий, что 65% памяти тратится впустую из-за неэффективного программирования. Да, это простое ванильное приложение, в котором должны быть реализованы все лучшие практики, и это тоже на широко известном фреймворке тратит впустую 65% памяти.

![pie-chart.PNG](Рис.: Диаграмма, сгенерированная HeapHero, показывающая, что 65% памяти тратится впустую приложением Spring Boot Pet Clinic

Анализ потери памяти
Из отчета можно заметить следующее:

15,6% памяти тратится впустую из-за повторяющихся строк
14,6% памяти тратится впустую из-за неэффективных примитивных массивов
14,3% памяти тратится впустую из-за дублирования примитивных массивов
12,1% памяти тратится впустую из-за неэффективных коллекций

Дублирующиеся строки
Основной причиной потери памяти в этом загрузочном приложении Spring (и в большинстве корпоративных приложений) является дублирование строк. Отчет показывает, сколько памяти теряется из-за дублирования строк, что это за строки, кто их создает и как их оптимизировать.

дубликаты-strings.PNG
Рис. Дублированные строки

Вы можете заметить, что 15,6% памяти тратится впустую из-за повторяющихся строк. Пожалуйста, обрати внимание

Строка Голди была создана 207 481 раз.
Строка «Посетить» была создана 132 308 раз. «Посещение» — это описание, которое мы упоминали в тестовом сценарии.
Строка «Бангалор» была создана 75 374 раза. Banglore — это название города, которое мы указали в тестовом сценарии.
«123123123» было создано 37 687 раз.
Строка «Махеш» была создана 37 687 раз.
Судя по всему, «Голди» — это имя питомца, которое было введено на экран с помощью тестового сценария. «Посещение» — это описание, введенное на экран с помощью тестового сценария. Точно так же и ценности. Но вопрос, почему столько тысяч раз создаются одни и те же строковые объекты.

Все мы знаем, что строки неизменяемы (т. е. после создания их нельзя изменить). Учитывая это, почему создаются эти многие тысячи повторяющихся строк?

Инструмент HeapHero также сообщает о пути кода, где создаются эти повторяющиеся строки.

дубликат-строки-холдинг.PNG
Рис. Кодовый путь, из которого происходят повторяющиеся строки

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

Неэффективные коллекции
Еще одна основная причина потери памяти в приложении Spring Boot Pet Clinic: неэффективная реализация коллекций. Ниже приведена выдержка из отчета HeapHero:

неэффективные-коллекции.PNG
Рис. Память теряется из-за неэффективных коллекций.

Вы можете заметить, что 99% LinkedHashSet в памяти не содержат никаких элементов. Если элементов нет, зачем вообще создавать LinkedHashSet? При создании нового объекта LinkedHashSet в памяти резервируется место для 16 элементов. Все пространство, зарезервированное для этих 16 элементов, теперь потрачено впустую. Если вы выполняете ленивую инициализацию LinedHashset, то этой проблемы не возникнет.

Плохая практика:

private LinkedHashSet<String, String> myHashSet = new LinkedHashSet();

public void addData(String key, String value) {

 myHashSet.put(key, value);
}

Лучшая практика:

private LinkedHashSet<String, String> myHashSet;

public void addData(String key, String value) {

      if (myHashSet == null) {

 myHashSet = new LinkedHashSet();
      }

myHashSet.put(key, value);
}

Точно так же другое наблюдение: 68% ArrayList содержат в себе только 1 элемент. При создании объекта ArrayList в памяти резервируется место для 10 элементов. Это означает, что 88% пространства элементов ArrayList 9 тратится впустую. Если вы можете инициализировать ArrayList с емкостью, этой проблемы можно избежать.

Плохая практика: инициализация коллекций по умолчанию.

new ArrayList();

Передовой опыт: инициализируйте коллекции с емкостью

 new ArrayList(1);

Память не дешевая
Можно возразить, что память такая дешевая, так зачем мне об этом беспокоиться? Справедливый вопрос. Но память моих друзей стоит недешево в эпоху облачных вычислений. Существует 4 основных вычислительных ресурса:
*ПРОЦЕССОР
*Память
*Сеть
*Хранилище

Ваше приложение может работать на десятках, тысячах серверов приложений, работающих на инстансах AWS EC2. Из упомянутых выше 4 вычислительных ресурсов, какой ресурс становится насыщенным в экземпляре EC2? Я прошу вас сделать здесь небольшую паузу, прежде чем читать дальше. Подумайте, какой ресурс насыщается первым.

Для большинства приложений это Память. Процессор всегда на 30-60%. Запасов всегда много. Трудно насытить сеть (если только ваше приложение не транслирует много видеоконтента). Таким образом, для большинства приложений в первую очередь насыщается память. Несмотря на то, что ЦП, хранилище и сеть используются недостаточно, только потому, что память переполняется, вы в конечном итоге выделяете все больше и больше экземпляров EC2. Это увеличит ваши вычислительные затраты в несколько раз.

С другой стороны, все без исключения современные приложения тратят впустую от 30 до 90% памяти из-за неэффективных методов программирования. Даже выше Spring boot pet Clinic без особой бизнес-логики тратит впустую 65% памяти. Реальные корпоративные приложения будут тратить столько же или даже больше. Таким образом, если вы можете написать код с эффективным использованием памяти, это снизит ваши вычислительные затраты. Поскольку память является первым ресурсом, который становится насыщенным, если вы сможете уменьшить потребление памяти, вы сможете запускать свое приложение на меньшем количестве экземпляров сервера. Возможно, вы сможете сократить 30–40% серверов. Это означает, что ваше руководство может сократить расходы на центр обработки данных (или провайдера облачного хостинга) на 30–40 %, а также затраты на техническое обслуживание и поддержку. Это может составить несколько миллионов/миллиардов долларов экономии средств.

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

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *