Так же, как мозг принципиально важен для жизни человека, память важна для компьютеров. Если у вашей системы будет недостаточно оперативной памяти, она не сможет выполнять задачи.
Причиной нехватки оперативной памяти и некоторых других пробоем с памятью может стать утечка памяти, и поэтому здесь мы разберем, как можно обнаружить утечки памяти и как с ними бороться.
Но для начала давайте разберемся, что такое утечка памяти и почему с ними нужно бороться.
1. Что такое утечки памяти?
Представьте парковку рядом с торговым центром, на которой припаркованы все автомобили покупателей, независимо от того, закончили они покупки или нет. Со временем на парковке не останется места для новых автомобилей, что приведет к пробкам и снижению общей эффективности торгового центра.
С компьютерами тоже самое!
Приложения на компьютерах, как и машины на стоянке, могут забыть освободить уже неиспользуемую память. Это создает дополнительную нагрузку на вашу память и не оставляет пространства для нормальной работы новых задач, что приводит к довольно распространенной ошибке, которая называется «утечка памяти».
Ниже приведен пример кода, демонстрирующий утечку памяти:
void memory_allocation() {
int *ptr = (int*)malloc(sizeof(int));
}
Код выше написан на С. Он выделяет некоторую память для целочисленной переменной и присваивает ей место в памяти по указателю ptr. Однако здесь нет кода, который бы освободил эту память, а это приведет к утечкам памяти.
def infinite_rec():
return infinite_rec()
Этот код написан на Python, и в нем не завершается функция. В результате такой код приведет к переполнению стека и утечкам памяти.
2. Распространенные причины утечек памяти
Невнимание программиста
Первая причина утечки памяти – невнимание программиста.
Зачастую программисты помещают данные в память, но забывают освободить ее, когда данные больше не нужны. В какой-то момент вся память оказывается забитой и в ней не остается места для намеченных задач, что приводит к тому, что мы называем «утечкой памяти».
Языки программирования
Если вы используете языки программирование без встроенной системы управления памятью, вы рискуете столкнуться с такой проблемой, как утечка памяти.
Такие языки программирования, как Java, имеют встроенные сборщики мусора, которые очищают память автоматически.
Но, например, в С++ нет встроенного сборщика мусора. В связи с этим вам, то есть программисту, придется очищать память вручную, что может привести к утечкам памяти, если вы вдруг забудете это сделать.
Чрезмерное использование кэша
Задачи, данные и приложения, которые используются чаще остальные, как правило, кэшируются для более быстрого доступа.
Если элементы кэшируются, но не очищаются, хотя уже устарели или больше не соответствуют вашим текущим шаблонам использования, это может привести к утечке памяти.
Глобальные переменные
Глобальные переменные хранят выделенные данные на протяжении всего времени существования приложения. А это значит, что, если вы будете использовать слишком много глобальных переменных, память будет использоваться в большим количестве и в течение длительного времени, что может вызвать утечки памяти.
Неэффективные структуры данных
Зачастую разработчики создают свои собственные структуры данных, чтобы реализовать свои функции. Однако, если эти структуры данных не могут освободить используемую память, могут возникнуть утечки памяти.
Незавершенные соединения
Незакрытые файлы, базы данных, незавершенные подключения и т.д. также могут привести к утечкам памяти.
3. Последствия утечек памяти
Низкая производительность. По мере роста количества утечек памяти, вы заметите, как производительность вашего приложения или системы начнет постепенно снижаться. А все потому, что для выполнения задач не будет хватать памяти, что, естественно, будет замедлять работу приложения.
Сбой приложений. По мере того, как количество утечек будет расти, приложениям все сильнее будет не хватать памяти. В какой-то момент, когда программе не будет хватить памяти, она просто выйдет из строя, что может привести к потере данных и сбою всего приложения.
Уязвимости системы безопасности. Если вы неправильно очистите конфиденциальные данные (например, пароли, личные данные или конфиденциальную информацию) из памяти после использования, они могут стать доступными для злоумышленников при утечке памяти.
Исчерпание ресурсов. Если приложениям не хватает места из-за утечек памяти, они начинают занимать больше места в вашей оперативной памяти. Таким образом, потребление ресурсов увеличивается, а общая производительность системы снижается.
4. Как обнаружить утечку памяти?
Ручная проверка кода
Просмотрите исходный код и найдите места, где память выделяется, но не очищается после использования. Ищите в коде переменные и объекты, которые используют память, но не освобождают ее после.
Помимо этого, следите за хранилищами данных, т.е. убедитесь, что структуры данных исправно управляют выделенной памятью.
Статический анализ кода
Различные инструменты статического анализа кода позволяют анализировать ваш исходный код на наличие утечек памяти.
Иногда они отслеживают в вашем коде распространенные шаблоны, правила и ошибки, чтобы заранее предвидеть утечки памяти до того, как они произойдут.
Инструменты динамического анализа
Эти инструменты используют динамический подход для анализа кода в процессе выполнения и обнаруживают, таким образом, утечки памяти.
Инструменты динамического анализа исследуют поведение объектов и функций во время выполнения и то, как они используют память. Именно поэтому эти инструменты могут обнаруживать утечки памяти с высокой точностью.
Профилировщики
Инструменты профилирования раскрывают то, как приложение использует память.
Вы, как разработчик, можете использовать эту информацию для того, чтобы проанализировать, как программа использует память, а также для оптимизации методов управления, чтобы предотвратить сбои приложений и проблемы с нехваткой памяти.
Специальные библиотеки
Некоторые языки имеют встроенные библиотеки для обнаружения утечек памяти в вашей программе, некоторые используют сторонние библиотеки.
Например, у Java есть встроенный сборщик мусора, который управляет памятью, а C++ управляет памятью с помощью CrtDbg.
Помимо этого, существуют библиотеки, например, LeakCanary, Valgrind, YourKit и т.д., которые позволяют устранять утечки памяти в различных приложениях.
5. Как бороться с утечками памяти?
Найдите утечку памяти
Для того, чтобы устранить утечку памяти, ее сначала нужно найти.
Чтобы определить, есть ли в приложении утечки памяти, вы можете проверить код вручную или воспользоваться каким-нибудь автоматизированным инструментов. Вы также можете воспользоваться и другими методами, рассмотренными выше.
Определите объект, который ее вызывает
После того, как вы убедитесь, что в приложении действительно есть утечка памяти, необходимо найти объекты и структуры данных, которые ее вызывают. Разберитесь, как им выделяется память и где они должны ее освободить.
Создайте тестовый пример
Итак, вы сузили круг до одного конкретного места, где и происходит утечка памяти. Создайте тестовый пример, чтобы убедиться, что вы правильно определили источник утечки памяти и что это утечка исчезнет, как только вы исправите ошибку.
Исправьте код
Добавьте соответствующий код, который будет освобождать «заблокированную» память от выявленных некорректных объектов. Если такой код уже есть, обновите его, чтобы убедиться, что он правильно освобождает используемую память.
Снова протестируйте
И снова, воспользуйтесь инструментами обнаружения утечек памяти или автоматизированными тестами, чтобы проверить, правильно ли работает приложение и не блокируется ли память.
Помимо этого, протестируйте приложение на производительность и функциональность, чтобы убедиться, что обновление кода не повлияло на другие части приложения.
6. Рекомендации, как избежать утечек памяти
Будьте ответственным программистом
Когда вы пишете код, вы всегда должны помнить о том, что должны освободить используемую память или указатели памяти. Это поможет минимизировать проблемы, связанные с утечками памяти.
Помните этот код? Как мы уже говорили в начале статьи, здесь отсутствует фрагмент кода, отвечающий за освобождение памяти, что и приводит к утечке.
void memory_allocation() {
int *ptr = (int*)malloc(sizeof(int));
}
А это то, как вы, будучи программистом, можете освободить память:
delete ptr;
Используйте «оборудованные» языки программирования
Такие языки программирования, как Java или Python, имеют встроенные библиотеки управления памятью, например, сборщики мусора, которые разбираются с утечками памяти автоматически.
Даже если вы упустите из виду какие-то моменты, эти встроенные инструменты помогут вам предотвратить потенциальные утечки памяти.
Так что, мой вам совет: используйте языки программирования со встроенными системами управления памятью.
Циклические ссылки
Избегайте циклических ссылок в вашей программе.
Циклические ссылки петляют по циклу объектов, которые ссылаются друг на друга. Например, объект А ссылается на объект В, объект В – на объект С, а объект С – снова на объект А, и так бесконечно. В результате циклические ссылки создают бесконечный цикл, который вызывает утечки памяти.
Минимизируйте использование глобальных переменных
Если вы беспокоитесь о том, насколько эффективно используется память, вам следует избегать использования глобальных переменных. Глобальные переменные используют вашу память на протяжении всего времени существования вашего приложения, а это не самый лучший подход к управлению памятью.
Так что, переключайтесь на локальные переменные. Они используют память максимально эффективно, так как освобождают память после завершения вызова функции.
Вот как выглядят глобальные переменные (используйте их только при необходимости):
int x = 5 // Global variable { // Глобальная переменная }
void func(){
print(x)
}
Но использовать все же стоит локальные переменные:
void func(){
int x = 5 // Local variable { // Локальная переменная }
print(x)
}
Ограничьте память кэша
Установите ограничение на объем памяти, который может использовать кэш. Иногда все задачи, которые вы выполняете в системе, отправляются в кэш-память, и весь этот накопленный кэш может привести к утечкам памяти.
Так что, ограничив объем кэша, вы можете предотвратить утечки памяти.
Хорошо тестируйте
Добавьте в этап тестирования тесты на наличие утечки памяти.
Автоматизируйте тестирования и охватите все пограничные случаи, чтобы обнаружить утечки памяти до того, как вы пустите код в производство.
Вооружитесь инструментами мониторинга
Используйте инструменты автоматического профилирования для того, чтобы отслеживать, как используется память. Постоянное отслеживание помогает выявлять потенциальные утечки и устранять их заблаговременно.
Вот несколько хороших инструментов: Visual Studio profiler, NET Memory profiler и JProfiler.
Заключение
Эффективное управление памятью помогает достичь максимальной производительности приложения, а такие вещи, как утечки памяти, просто нельзя игнорировать. Для эффективного управления памятью утечки необходимо устранять и не допускать их появления в будущем. Эта статья как раз посвящена тому, что вы можете для этого сделать.
Мы показали вам различные методы, с помощью которых вы можете обнаружить утечки памяти, проверенные способы, как их устранить, а также предоставили вам рекомендации, которые помогут вам избежать утечек памяти в будущем.