Как найти утечку памяти
Перейти к содержимому

Как найти утечку памяти

  • автор:

Найти и обезвредить: утечки памяти в Node.js

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

Это довольно распространенная проблема. Дело в том, что многие разработчики пренебрегают управлением памятью из-за неправильных представлений об ее автоматическом выделении и освобождении в современных высокоуровневых языках программирования, например JavaScript.

Своевременно же не решенный вопрос ее утечек может обернуться резким снижением производительности приложения вплоть до невозможности его нормального использования.

Пространство Интернета постоянно пополняется сложными жаргонизмами, в которых весьма непросто разобраться. Данная статья будет построена по другому принципу — просто и понятно. Вы узнаете о том, что такое утечки памяти и каковы их причины; как их легко обнаружить и диагностировать с помощью Chrome Developer Tools.

Начнем с того, что ключ к их пониманию лежит в понимании принципов управления памятью в Node.js. А это, в свою очередь, означает, что мы должны разобраться, как это управление осуществляется движком V8, используемым Node.js для JavaScript.

Вкратце напомню вам структуру памяти в V8.

Главным образом она делится на две области: стек (stack) и кучу (heap).

1.Стек — это область памяти, в которой хранятся статические данные, включающие фреймы методов/функций, примитивные значения и указатели на объекты. Он управляется ОС.

2.Куча — это самая большая область памяти, в которой V8 хранит объекты или динамические данные. Здесь же происходит сборка мусора.

Цитируя Дип К Сасидхаран, разработчика и одного из авторов книги “Развитие полного стека с JHipster”, отметим, что

“V8 управляет памятью кучи с помощью сборки мусора. Проще говоря, он освобождает память, используемую висячими объектами, т.е. объектами, на которые нет прямых или косвенных (через ссылку в другом объекте) ссылок из стека, для освобождения пространства с целью создания нового объекта.

Сборщик мусора в V8 отвечает за восстановление неиспользуемой памяти для повторного ее применения в процессе работы движка. Сборка мусора происходит по поколениям (объекты в куче распределяются по группам в зависимости от времени жизни и удаляются на разных этапах). В V8 существуют два этапа и три разных алгоритма сборки мусора”.

Что такое утечки памяти?

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

И вот мы имеем неиспользуемый фрагмент памяти. Со временем результатом накопления таких фрагментов станет ваше приложение, сигнализирующее о нехватке памяти для работы или даже ОС, требующая места для выделения памяти. А все это вместе чревато торможениями и/или выходом приложения или даже ОС из строя.

В чем же причина утечек памяти в JS?

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

Рассмотрим несколько самых распространенных причин:

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

2. Множественные ссылки. Ситуации, когда на один и тот же объект ссылаются несколько объектов, также могут вызвать утечку памяти при условии, что одна из ссылок становится висячей.

3. Замыкания. Замыкания JavaScript обладают превосходным свойством запоминать окружающий их контекст, вследствие чего ссылки на крупные объекты кучи, используемые в них, сохраняются дольше, чем требуется.

4. Таймеры и события. Использование setTimeout , setInterval , Observers и слушателей событий может вызвать утечки памяти в том случае, если ссылки на объекты кучи хранятся в их обратных вызовах без правильной обработки.

Лучшие практики для предотвращения утечек памяти

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

Сокращение использования глобальных переменных

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

Обходимся без случайных глобальных переменных

Когда вы присваиваете значение необъявленной переменной, JavaScript по умолчанию определяет ее как глобальную. Это может произойти по ошибке и привести к утечке памяти. Подобное может случиться в результате присвоения переменной к this .

Во избежание таких сюрпризов, всегда пишите код JavaScript в режиме strict и используйте нотацию 'use strict'; в начале файла JS.

В режиме strict выше приведенный пример приведет к ошибке. Однако при использовании ES модулей и компиляторов, таких как TypeScript или Babel, нет необходимости включать данный режим, так как он будет задействован по умолчанию. В последних версиях Node.js вы можете активировать режим strict глобально, сопроводив выполнение команды node флагом —use_strict .

И наконец, помните, что не следует привязывать глобальное this к функциям, использующим методы bind или call , так как это лишает использование режима strict всякого смысла.

Умеренное использование глобальной области видимости

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

  1. Минимизируйте использование глобальной области видимости. Вместо этого рассмотрите возможность применения локальной области внутри функций, так как они будут удалены в процессе сборки мусора для освобождения памяти. Если вам вынужденно приходится прибегать к использованию глобальной переменной, то задайте ей значение null , когда в ней уже не будет необходимости.
  2. Используйте глобальные переменные только для констант, кэша и переиспользуемых объектов-одиночек. Не стоит применять их в целях избежания передачи значений в коде. Для обмена данными между функциями и классами передавайте значения в качестве параметров или атрибутов объектов.
  3. Не храните крупные объекты в глобальной области видимости. Если же вам приходится это делать, то не забудьте определить их как null, когда они более не нужны. В отношении объектов кэша рекомендуется установить обработчик для периодической очистки, препятствующий их неограниченному росту.

Эффективное использование стека

Максимально возможное использование переменных стека способствует эффективной и производительной работе памяти, так как доступ к стеку происходит гораздо быстрее, чем к куче. Это также позволяет избежать случайных утечек памяти.

Конечно, использование исключительно статических данных непрактично. В реальных приложениях нам приходится работать со многими объектами и динамическими данными. Но мы можем оптимизировать применение переменных стека при помощи ряда приемов:

1.Избегайте использования ссылок переменных стека на объекты кучи по мере возможности и не храните неиспользуемые переменные;

2.Деструктуризируйте и используйте только необходимые поля объектов или массивов вместо того, чтобы целиком передавать их функциям, замыканиям, таймерам и обработчикам событий. Тогда ссылки на объекты уже не будут оставаться в замыканиях. Передаваемые поля могут быть в основном примитивами, которые будут храниться в стеке.

Эффективное использование кучи

В любом реальном приложении мы так или иначе будем использовать кучу, но с помощью следующих рекомендаций можно сделать работу с ней более эффективной:

1.По возможности копируйте объекты вместо того, чтобы передавать ссылки. Их передача возможна только в том случае, если объект крупный или операция копирования требует больших затрат.

2.По максимуму обходитесь без мутаций объекта. Вместо этого для их копирования используйте распространение объекта или Object.assign .

3.Вместо создания множественных ссылок на объект просто его скопируйте.

4.Используйте переменные с коротким жизненным циклом.

5.Старайтесь не создавать огромные деревья объектов. Если же это неизбежно, то обеспечьте им короткий жизненный цикл в локальной области видимости.

Грамотное использование замыканий, таймеров и обработчиков событий

Как уже было отмечено ранее, замыкания, таймеры и обработчики событий — это те области, где могут произойти утечки памяти. Начнем с замыканий, как наиболее часто встречающихся в коде JavaScript. Посмотрим на следующий код команды Meteor, который приводит к утечке памяти, так как переменная longStr не подлежит удалению и увеличивает объём занимаемой памяти.

Выше обозначенный код создает несколько замыканий, которые удерживают ссылки на объекты. В этом случае устранение утечки памяти возможно путем определения originalThing как null в конце выполнения функции replaceThing . Подобных ситуаций тоже можно избежать, создавая копии объектов и соблюдая выше описанный немутабельный подход.

Когда дело касается таймеров, всегда передавайте копии объектов и обходитесь без мутаций. По окончании работы таймеров проводите их очистку с помощью методов clearTimeout и clearInterval .

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

Заключение

В настоящее время утечки памяти в JavaScript не являются такой уж большой проблемой, как бывало раньше, благодаря эволюции движков JS и улучшениям в языке. Но если мы не будем внимательны, то они по-прежнему будут происходить и приводить к снижению производительности и сбоям в работе приложения/ОС.

Во-первых, чтобы убедиться, что наш код не приводит к утечкам памяти в приложении Node.js, нужно разобраться в принципах ее управления движком V8. Во-вторых, важно понять, что послужило их причиной.

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

Выявление утечек памяти в C++

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

Простейшая программа с утечкой памяти:

В данном участке кода утечка памяти происходит из-за отсутствия оператора delete[] для массива p.

В статье «Анализ программ и компиляторов в Compiler Explorer» показано, что в ряде случаев утечки памяти можно найти средствами статического анализа программ, однако такие инструменты нередко дают «ложные срабатывания», а иногда — не обнаруживают утечку.

В этой статье рассмотрены:

1 Обнаружение утечек с библиотекой CRT

Библиотека CRT доступна в операционной системе Windows, она у вас уже есть если вы используете Microsoft Visual Studio. Для подключения анализатора памяти достаточно добавить пару макросов и собрать проект в отладочном режиме:

Видно, что первая группа макросов добавляется в самое начало вашей программы. За счет этих макросов все обращения в функциям new, malloc, free и delete заменяются на другие версии, которые помимо выделения/освобождения памяти сохраняют дополнительную информацию (сколько и где было выделено). Макрос _CrtDumpMemoryLeaks добавляется в конец программы (перед завершением работы) и выводит информацию о текущем состоянии памяти.

Для приведенной выше программы в окно отладки будет выведено следующее:

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

2 Использование Visual Leak Detector

VLD поставляется в виде плагина для Microsoft Visual Studio, для его установки:
1) Скачиваем с официального сайта Microsoft и устанавливаем.
2) Добавляем в свойствах проекта во «включаемые каталоги» путь к каталогу include:
C:\ProgramFiles(x86)\VisualLeakDetector\include .
3) Добавляем в свойствах проекта в Каталог библиотек для win32 или win64 : путь к катлогу lib:

4) Добавляем в начало главного файла ( main.cpp ) #include<vld.h>
Получается так:

Все говото, утечки ищутся и выводятся в консоль отладки:

Видно, что VLD выводит информацию о стеке вызовов, но формат вывода крайне неудобный. Узнать в какой строке произошла утечка памяти совсем непросто.

3 Работа с Valgrind memcheck

Valgrind предоставляет множество инструментов для динамического анализа, поиском утечек памяти это не ограничивается. Работой с памятью занимается модуль memcheck. Для его использования необходимо:
1) Сстановить valgrind:
sudo apt install valgrind

2) Скомпилировать программу в debug-режиме и запустить ее через valgrind:
valgrind ./my_program
При таком запуске будет выведено сколько памяти было потеряно. Чтобы увидеть, где была выделена память, необходимо добавить опцию
—leak-check=full .

Результаты работы memcheck для нашего примера:

4 Как это устроено внутри

Подключение CRT приводит к оборачиванию функций работы с памятью в что-то такое:

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

Да и зачем этим заниматься если его готовый CRT? В свою очередь, Visual Leak Detector представляет собой обертку над CRT.

Утилита Valgrind работает совсем иначе — ей не требуется модифировать исходный код вашей программы. Вместо этого программа запускается на виртуальном (моделируемом) процессоре в виртуальном окружении. Это окружение точно знает сколько памяти потребила программа, а процессор — в каких инструкциях эта память была запрошена. За счет этого valgrind позволяет не только обнаружить утечки памяти, но и получить статистику кэш-попаданий (модуль cachegrind), например. Однако, тут внутреннее устройство valgrind показано крайне упрощенно, а на самом деле все гораздо сложнее. Тем не менее, это один из лучших инструментов поиска утечек в мире.

4 Более сложный пример

Возможно, вам кажется что проблем с поиском утечек не возникает, тогда посмотрите такой пример:

Сколько времени у вас уйдет на поиск всех утечек? Ведь после возврата строки delete p в программе появятся другие утечки. Для начала — не будет вызывать деструктор

Cat() ведь деструктор

Animal() объявлен невиртуальным. После исправления этой ошибки — мы получим еще одну, ведь в классе Cat память выделяется через new , а освобождается через free .

Результаты применения всех трех рассмотренных инструментов примерно одинаковы (разве что VLD не выводит информацию о строке возникновения ошибки). Ниже приведен вывод valgring memcheck:

Видно, что обнаруживается 3 утечки, так как на 3 аллокации не приходится ни одной операции освобождения. После добавления delete в функцию main получаем одну утечку. Теперь на 3 аллокации приходится две операции освобождения. Найдена лишь одна утечка, однако на самом деле — вообще не вызывается деструктор

Cat() , поэтому после замены free на delete в нем — результат работы не изменится. А вот после добавления виртуального деструктора — утечек найдено не будет.

Понятно, что описанные инструменты сильно упрощают жизнь программисту. Найти без них течки памяти в чужом коде из 10 тысяч строк кода — задача крайне сложная, а с ними — решается элементарно. Однако, вывод результатов их работы очень неинформативный. Сравните полученные результаты с выводом статических анализаторов (в обоих статьях используются одинаковые примеры).

Поиск, устранение и предупреждение утечек памяти в C# .NET: 8 лучших практик

Для будущих студентов курса «Разработчик C#» и всех интересующихся подготовили перевод полезного материала.

Также приглашаем поучаствовать в открытом вебинаре на тему «Методы LINQ, которые сделают всё за вас» — на нем участники обсудят шесть представителей семейства технологий LINQ, три составляющих основной операции запроса, отложенное и немедленное выполнение, параллельные запросы.

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

Умение обнаруживать, исправлять и предупреждать утечки памяти — очень важный навык. Здесь я перечислю 8 лучших практик, используемых мной и моими коллегами старшими .NET разработчиками, которые и вдохновили меня написать эту статью. Эти методы научат вас определять, когда в приложении возникает утечка памяти, находить и исправлять ее. Наконец, я включил в статью стратегии для мониторинга и отчета об утечках памяти в уже развернутых программах.

Что из себя представляют утечки памяти в .NET

В среде со сборкой мусора термин «утечка памяти» представляется немного контринтуитивным. Как может произойти утечка памяти, когда есть сборщик мусора (GC — garbage collector), который берет на себя задачу высвобождения памяти?

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

Вторая причина заключается в том, что вы каким-то образом выделяете неуправляемую память (без сборки мусора) и не освобождаете ее. Сделать это не так уж и сложно. В самой .NET есть множество классов, которые выделяют неуправляемую память. Практически все, что связано с потоками, графикой, файловой системой или сетевыми вызовами, делает это под капотом. Обычно эти классы реализуют метод Dispose , который освобождает память (мы поговорим об этом позже). Вы можете легко выделить неуправляемую память самостоятельно с помощью специальных классов .NET .Например, Marshal или PInvoke (пример этого будет ниже).

Давайте же перейдем к моему списку лучших практик:

1. Обнаружение утечек памяти с помощью окна средств диагностики

Если вы перейдете в Debug | Windows | Show Diagnostic Tools, вы увидите это окно. Как и я когда-то, вы, вероятно, уже видели это окно после установки Visual Studio, сразу же закрыли его и никогда больше о нем не вспоминали. Окно средств диагностики может быть весьма полезным. Оно может помочь вам легко обнаружить 2 проблемы: утечки памяти и GC Pressure (давление на сборщик мусора).

Когда у вас есть утечки памяти, график использования памяти процессом (Process Memory) выглядит следующим образом:

По желтым линиям, идущим сверху, вы можете наблюдать, как сборщик мусора пытается высвободить память, но загруженность памяти все-равно продолжает расти.

В случае GC Pressure, график использования памяти процессом выглядит следующим образом:

GC Pressure — это когда вы создаете и удаляете новые объекты настолько быстро, что сборщик мусора просто не успевает за вами. Как вы видите на картинке, объем потребляемой памяти близок к своему пределу, а сборка мусора происходит очень часто.

С помощью этого метода вы не сможете найти определенные утечки памяти, но вы навскидку можете обнаружить, что у вас есть проблема с утечкой памяти, что само по себе уже несет пользу. В Visual Studio Enterprise окно средств диагностики также включает встроенный профилировщик памяти, который позволяет обнаружить конкретную утечку. Мы поговорим о профилировании памяти в третьем пункте.

2. Обнаружение утечек памяти с помощью диспетчера задач, Process Explorer или PerfMon

Второй самый простой способ обнаружить серьезные проблемы с утечками памяти — с помощью диспетчера задач (Task Manager) или Process Explorer (от SysInternals). Эти инструменты могут показать объем памяти, который использует ваш процесс. Если она постоянно увеличивается со временем, возможно, у вас утечка памяти.

PerfMon немного сложнее в использовании, но у него есть хороший график потребления памяти с течением времени. Вот график моего приложения, которое бесконечно выделяет память, не освобождая ее. Я использую счетчик Process | Private Bytes.

Обратите внимание, что этот метод заведомо ненадежен. Вы можете наблюдать увеличение потребления памяти только потому, что еще не отработал сборщик мусора. Также стоит вопрос об общей и приватной памяти, поэтому вы можете упустить утечки памяти и/или диагностировать утечки, которые не являются вашими собственными (объяснение). Наконец, вы можете принять утечку памяти за GC Pressure. В этом случае у вас нет утечек памяти, но вы создаете и удаляете объекты так быстро, что сборщик мусора не поспевает за вами.

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

3. Использование профилировщика памяти для обнаружения утечек

Профилировщик в работе с утечками памяти подобен ножу шеф-повара. Это основной инструмент для их поиска и исправления. Хотя другие методы могут быть проще в использовании или дешевле (лицензии на профилировщики стоят дорого), все таки стоит овладеть навыком работы хотя с бы один профилировщиком памяти, чтобы при необходимости эффективно решать проблемы утечек памяти.

Вот несколько довольно известных профилировщиков для .NET: dotMemory, SciTech Memory Profiler и ANTS Memory Profiler. Также есть «бесплатный» профилировщик, если у вас стоит Visual Studio Enterprise.

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

Вы можете увидеть, сколько аллоцировано экземпляров каждого типа, сколько памяти они занимают и путь ссылки на GC Root.

GC Root — это объект, который сборщик мусора не может освободить, поэтому все, на что ссылается GC Root, также не может быть освобождено. Статические и локальные объекты, текущие активные потоки, являются GC Roots. Подробнее об этом читайте в статье «Сборка мусора в .NET».

Самый быстрый и полезный метод профилирования — это сравнение двух снапшотов, в которых память должна вернуться в одно и то же состояние. Первый снимок делается перед операцией, а второй после выполнения операции. Например, вы можете повторить эти шаги:

Начните с какого-либо состояния бездействия (Idle state) в вашем приложении. Это может быть Главное меню или что-то в этом роде.

Сделайте снапшот с помощью профилировщика памяти, присоединившись к процессу или сохранив дамп.

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

Сделайте второй снапшот.

Сравните оба снапшота с помощью своего профилировщика.

Изучите New-Created-Instances, возможно, это утечки памяти. Изучите «path to GC Root» и попытайтесь понять, почему эти объекты не были освобождены.

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

4. Используйте «Make Object ID» для поиска утечек памяти

В моей последней статье 5 методов, позволяющих избежать утечек памяти из-за событий в C# .NET, которые вы должны знать, я показал способ найти утечку памяти, поместив точку останова в класс Finalizer. Я покажу вам похожий метод, который еще проще в использовании и не требует изменения кода. Здесь используется функция отладчика Make Object ID и окно непосредственной отладки (Immediate Window).

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

Поместите точку останова туда, где создается экземпляр класса.

Наведите курсор на переменную, чтобы открыть всплывающую подсказку отладчика, затем щелкните правой кнопкой мыши и используйте Make Object ID . Вы можете ввести в окне Immediate $1 , чтобы убедиться, что Object ID был создан правильно.

Завершите сценарий, который должен был освободить ваш экземпляр от ссылок.

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

5. В появившемся окне непосредственной отладки введите $1 . Если оно возвращает null , значит, сборщик мусора собрал ваш объект. Если нет, у вас утечка памяти.

Здесь я отлаживаю сценарий с утечкой памяти:

А здесь я отлаживаю аналогичный сценарий, в котором нет утечек памяти:

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

Важно: этот метод не работает в отладчике .NET Core 2.X (проблема). Принудительная сборка мусора в той же области, что и выделение объекта, не освобождает этот объект. Вы можете сделать это, приложив немного больше усилий, спровоцировав сборку мусора в другом методе вне области видимости.

5. Избегайте известных способов заиметь утечки памяти

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

Вот некоторые из наиболее распространенных подозреваемых:

События (Events) в .NET печально известны тем, что вызывают утечки памяти. Вы можете подписаться на событие, даже не подозревая, что это вызовет серьезную утечку памяти. Эта тема настолько серьезная, что я посвятил ей целую статью: 5 методов, позволяющих избежать утечек памяти из-за событий в C# .NET, которые вы должны знать

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

Кэширование — любой тип механизма кэширования может легко вызвать утечку памяти. Кэширую информацию в памяти, в конечном итоге он переполнится и вызовет исключение OutOfMemory. Решением может быть периодическое удаление старых элементов или ограничение объема кэширования.

Привязки WPF могут быть опасными. Практическое правило — всегда выполнять привязку к DependencyObject или к INotifyPropertyChanged. Если вы этого не сделаете, WPF создаст сильную ссылку на ваш источник привязки (то есть ViewModel) из статической переменной, что приведет к утечке памяти. Дополнительную информацию о WPF утечках можно найти в этом полезном треде StackOverflow.

Захваченные члены. Может быть достаточно очевидно, что метод обработчика событий подразумевает, что на объект ссылаются, но когда переменная захвачена анонимным методом — на нее также ссылаются. Вот пример такой утечки памяти:

Потоки, которые никогда не завершаются. Live Stack каждого из ваших потоков считается GC Root. Это означает, что до тех пор, пока поток не завершится, любые ссылки из его переменных в стеке не будут собираться сборщиком мусора. Это также включает таймеры. Если обработчик тиков вашего таймера является методом, то объект метода считается ссылочным и не собирается. Вот пример такой утечки памяти:

Подробнее об этом читайте в моей статье 8 способов вызвать утечки памяти в .NET.

6. Используйте шаблон Dispose для предотвращения утечек неуправляемой памяти

Ваше приложение .NET постоянно использует неуправляемые ресурсы. Сама платформа .NET в значительной степени полагается на неуправляемый код для внутренних операций, оптимизации и Win32 API. Каждый раз, когда вы используете потоки, графику или файлы, например, вы, вероятно, исполняете неуправляемый код.

Классы .NET Framework , использующие неуправляемый код, обычно реализуют IDisposable . Это связано с тем, что неуправляемые ресурсы должны быть явно освобождены, а это происходит в методе Dispose . Ваша единственная задача — не забыть вызвать метод Dispose . Если возможно, используйте для этого оператор using .

Оператор using за кулисами преобразует код в оператор try / finally , где метод Dispose вызывается в finally .

Но даже если вы не вызовете метод Dispose , эти ресурсы будут освобождены, поскольку классы .NET используют шаблон Dispose. Это означает, что если Dispose не был вызван раньше, он вызывается из Finalizer , когда объект собирается сборщиком мусора. То есть, если у вас нет утечки памяти и действительно вызывается Finalizer .

Когда вы сами выделяете неуправляемые ресурсы, вам определенно следует использовать шаблон Dispose . Вот пример:

Смысл этого шаблона — разрешить явное удаление ресурсов. А также чтобы добавить гарантии того, что ваши ресурсы будут удалены во время сборки мусора (в Finalizer ), если Dispose() не был вызван.

GC.SuppressFinalize(this) также имеет важное значение. Она гарантирует, что Finalizer не будет вызван при сборке мусора, если объект уже был удален. Объекты с Finalizer-ами освобождаются иначе и намного дороже. Finalizer добавляется к F-Reachable-Queue , которая позволяет объекту пережить дополнительную генерацию сборщика мусора. Есть и другие сложности.

7. Добавление телеметрии памяти из кода

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

Из самого приложения мы можем получить много информации. Получить текущую используемую память очень просто:

Для получения дополнительной информации вы можете использовать PerformanceCounter — класс, который используется для PerfMon :

Для более глубокого тестирования профилировщики памяти, такие как .NET Memory Profiler от SciTech и dotMemory, предоставляют тестовый API:

Заключение

Не знаю, как у вас, но моя цель, поставленная на новый год, такова: лучшее управление памятью.

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

ИСПРАВЛЕНИЕ: утечки памяти в Windows 10 [Полное руководство]

Самый большой враг памяти ПК — это утечка памяти. Существует множество причин утечки памяти, но наиболее распространенной является оплошность программирования.

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

Что такое утечки памяти в Windows?

Утечка памяти означает потерю оперативной памяти в Windows, вызванную программой или приложением.

Каждый запущенный процесс в Windows занимает определенное количество оперативной памяти. Проблема полностью программная.

Есть программы, которые более требовательны и требуют большего использования ОЗУ для правильной работы, например Google Chrome или Adobe Photoshop, а есть менее требовательные программы, которые фактически занимают меньший объем памяти.

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

Что такое оперативная память и как ее используют программы?

RAM (оперативная память) — это относительно небольшой объем памяти, в которой хранятся данные запущенных процессов.

Программы хранят данные в оперативной памяти временно, фактически только во время работы. Итак, когда вы перезагружаете компьютер, ОЗУ опустошается. Каждая программа хранит свою информацию о работе в оперативной памяти.

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

Как исправить утечку памяти в Windows 10?

1. Перезагрузите компьютер.

утечка памяти хром

  1. Нажмите клавиши CTRL + SHIFT + ESC, чтобы открыть диспетчер задач .
  2. Перейдите на вкладку « Процессы » и посмотрите, какая программа использует больше всего памяти.
  3. Просто нажмите Завершить процесс , чтобы закрыть эту программу.

Теперь программа закрыта, но проблема еще не решена, потому что объем памяти, первоначально запрошенный этой программой, по-прежнему недоступен для других процессов.

Лучшее решение для этого — просто перезагрузить компьютер, и утечка памяти не появится, пока вы не откроете проблемную программу в следующий раз.

В ОЗУ хранятся данные только о запущенных процессах, когда компьютер выключен. Поэтому, когда вы перезагружаете компьютер, ОЗУ опустеет, и проблема с утечкой памяти исчезнет.

2. Используйте встроенные инструменты Windows 10.

Windows 10 утечка памяти 1

  1. Перейдите в Поиск, введите Средство диагностики памяти и откройте его.
  2. Выберите « Перезагрузить сейчас»,проверьте наличие проблем и не забудьте сохранить свою работу перед перезапуском.

В Windows 10 есть собственные встроенные средства диагностики, которых часто бывает достаточно для проведения точного анализа, который поможет вам определить причину проблемы.

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

  1. Перейдите в « Поиск», введите « Монитор ресурсов» и откройте его.
  2. Это позволяет вам просматривать данные о вашей системе в реальном времени.

3. Проверьте обновления драйверов.

утечка памяти javascript

  1. Перейдите в Поиск, введите Диспетчер устройств и откройте его.
  2. Проверьте все драйверы, рядом с которыми стоит желтый восклицательный знак .
  3. Щелкните его правой кнопкой мыши и выберите « Обновить драйвер»…
  4. Следуйте инструкциям мастера на экране.

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

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

Но если вы не знаете, какой именно драйвер следует обновить, проверка каждого драйвера по отдельности — это слишком большая работа. Итак, вам следует попробовать другой метод обновления драйверов в Windows 10.

DriverFix автоматически обновляет драйверы

Мы настоятельно рекомендуем инструмент DriverFix для обновления драйверов, чтобы избежать необратимого повреждения вашего компьютера из-за загрузки неправильных версий драйверов вручную.

После установки этот замечательный инструмент проверит версии установленных драйверов по своей облачной базе данных последних версий и автоматически загрузит обновления.

Все, что вам нужно сделать, это дождаться завершения сканирования.

Имейте в виду, что обновление драйверов — это сложная процедура. Если вы не будете осторожны, вы можете нанести непоправимый ущерб своей системе, загрузив неправильные версии драйверов.

Однако мы рекомендуем вам загрузить этот инструмент для обновления драйверов (на 100% безопасный и протестированный нами), чтобы сделать это автоматически. Таким образом, вы предотвратите утечку памяти и даже необратимое повреждение вашего ПК.

DriverFix

DriverFix

4. Удалите вредоносное ПО.

Точно так же, как устаревшие драйверы, вредоносные программы и другие виды вредоносного ПО являются причиной многих известных проблем в Windows, и утечки памяти не являются исключением.

Итак, если ваш компьютер заражен вредоносным ПО, он почти наверняка не будет работать хорошо (в зависимости от типа вредоносного ПО).

Единственное, что можно сделать в этом случае, — это очистить наши компьютеры от нежелательных гостей.

Мы рекомендуем Bitdefender Antivirus Plus — надежную антивирусную программу, которая защищает ваш компьютер от вирусов, троянов, вредоносных программ, шпионского ПО и других угроз в Интернете, таких как руткиты или программы-вымогатели.

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

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

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

Bitdefender Antivirus Plus

Bitdefender Antivirus Plus

5. Настройте на лучшую производительность

Windows 10 память

  1. Щелкните правой кнопкой мыши « Этот компьютер» на рабочем столе.
  2. Выберите Расширенные настройки системы.
  3. Перейдите на вкладку Advanced .
  4. Нажмите « Настройки» в разделе « Производительность».
  5. Просто отметьте опцию Adjust for best performance .
  6. Щелкните ОК.
  7. Перезагрузите компьютер.

6. Отключите программы, запущенные при запуске.

Windows 10 утечка памяти 7

  1. Нажмите клавиши CTRL + SHIFT + ESC, чтобы открыть диспетчер задач .
  2. Перейдите на вкладку Автозагрузка .
  3. Щелкните программу, которую хотите отключить, и выберите « Отключить».
  4. Перезагрузите компьютер.

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

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

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

7. Дефрагментация жестких дисков.

утечка памяти Windows 7

  1. Перейдите на этот компьютер .
  2. Щелкните правой кнопкой мыши текущий системный жесткий диск (скорее всего, C 🙂 .
  3. Перейдите на вкладку « Инструменты » и нажмите « Оптимизировать».
  4. Выберите диск, который нужно дефрагментировать, и выберите « Анализировать».
  5. Дождитесь завершения процесса.
  6. Перезагрузите компьютер.

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

8. Взлом реестра.

  1. Перейдите в раздел «Поиск» , введите regedit и выберите « Редактор реестра» .
  2. Найдите следующий путь:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management

  1. Найдите ClearPageFileAtShutDown и измените его значение на 1.
  2. Сохранить изменения.
  3. Перезагрузите компьютер.

Не можете получить доступ к редактору реестра? Ознакомьтесь с этим руководством и быстро решите проблему.

9. Отключить Runtime Broker.

  1. Нажмите клавиши CTRL + SHIFT + ESC, чтобы открыть диспетчер задач .
  2. Найдите процесс Runtime Broker и щелкните его.
  3. Перейти к Отключить.

Runtime Broker — это процесс, который помогает системе управлять разрешениями на вашем ПК для приложений из Microsoft Store.

По умолчанию Runtime Broker должен использовать небольшой объем памяти, но из-за возможного сбоя приложения этот процесс может значительно замедлить работу вашего ПК.

10. Отключите Superfetch.

Windows 10 утечка памяти 11

  1. Перейдите в Поиск , введите services.msc и откройте Службы.
  2. Найдите процесс под названием Superfetch.
  3. Щелкните его правой кнопкой мыши и выберите « Свойства».
  4. Выберите « Остановить» и выберите « Отключить» в раскрывающемся меню « Тип запуска» .
  5. Перезагрузите компьютер.

Superfetch — еще одна служба Windows, цель которой — оптимизировать производительность системы. Этот процесс позволяет Windows управлять объемом оперативной памяти, сокращать время загрузки и повышать эффективность загрузки приложений.

Отключать Superfetch не рекомендуется, но вы можете поэкспериментировать с ним, если хотите определить, действительно ли это замедляет работу вашего ПК.

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

11. Отключите советы и рекомендации Windows

Windows 10 утечка памяти 10

  1. Перейдите в меню «Пуск» и нажмите « Настройки».
  2. Выберите Система и выберите Уведомления и действия.
  3. Найдите Получайте советы, рекомендации и предложения при использовании Windows и снимите флажок.

Советы и рекомендации по Windows 10 действительно полезны для новых пользователей. Эта функция показывает им, как использовать систему, а также некоторые дополнительные полезные параметры.

Утечки памяти нет, но система все еще работает медленно? Добавьте больше оперативной памяти!

Если вы недавно столкнулись с этой проблемой на своем ПК, попробовали все наши решения, но ваш компьютер по-прежнему работает медленно, проблема, вероятно, связана с фактическим объемом оперативной памяти.

Если на вашем ПК недостаточно оперативной памяти для удовлетворения всех требований, лучшим доступным решением является обновление оперативной памяти, если вы хотите, чтобы ваш компьютер работал нормально.

При увеличении объема оперативной памяти ваша системная память станет больше, и она сможет обрабатывать еще более сложные операции.

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

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

Примечание редактора : этот пост был первоначально опубликован в октябре 2016 года и с тех пор был переработан и обновлен в сентябре 2020 года для обеспечения свежести, точности и полноты.

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

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