Set tmp d garbage что она делает
Перейти к содержимому

Set tmp d garbage что она делает

Введение в сборку мусора .NET

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

КДПВ

КДПВ

Сборщик мусора в .NET предрекал конец ручного управления памятью и защиту от ее утечек. Идея в том, что при наличии сборщика мусора, работающего в фоновом режиме, разработчикам больше не нужно беспокоиться о необходимости управления жизненным циклом объектов — сборщик сам позаботится о них, когда они станут не нужны.

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

Как работает сборщик мусора

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

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

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

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

Сами по себе корни не являются объектами, они представляют собой ссылки на объекты. Любой объект, на который ссылается корень, автоматически переживет следующую сборку мусора. В .NET существует четыре основных вида корней:

Локальные переменные ссылочного типа в методе, который выполняется в данный момент.

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

Статические поля также всегда считаются корнями. Объекты, на которые они ссылаются, могут быть доступны в любое время классу, который их объявил, или остальной части программы, если они объявлены, как public . Поэтому .NET всегда будет держать их в памяти. При этом поля, объявленные как ThreadStatic, будут существовать только до тех пор, пока выполняется использующий их поток.

Управляемые объекты, переданные в неуправляемую библиотеку через Interop.

Если управляемый объект передается в неуправляемую библиотеку COM+ через Interop, то он станет корневым объектом с подсчетом ссылок. Это происходит потому, что COM+ не выполняет сборку мусора. Вместо этого он использует систему подсчета ссылок. Как только библиотека COM+ завершает работу с объектом, устанавливая счетчик ссылок в 0, он перестает быть корневым и может быть удален.

Ссылки на объекты с финализатором.

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

Граф объектов

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

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

Граф связей между объектами и корнями (корни обозначены как "GC root")

Граф связей между объектами и корнями (корни обозначены как «GC root»)

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

Древовидное представление связей относительно корня GC root 2

Древовидное представление связей относительно корня GC root 2

Это упрощает представление о том, как объекты располагаются в памяти, удобно при написании приложений и при использовании отладчика. Однако из-за этого легко забыть, что объект может быть связан более, чем с одним корнем. Именно из-за этого обычно и происходят утечки памяти в .NET — разработчик забывает или не понимает, что объект привязан более, чем к одному корню. Например, в случае, показанном на схеме выше, установка корня GC root 2 в null на самом деле не позволит сборщику мусора удалить ни одного объекта. Это видно при просмотре полного графа, но не понятно при изучении дерева.

Профилировщик памяти позволяет взглянуть на граф иначе — как на дерево, начинающееся с какого-либо корневого объекта (не следует путать корни сборщика мусора и корневые объекты дерева). Следуя по ссылкам, указывающим на объекты дерева начиная с корневого (т. е. в обратном направлении), мы можем поместить в его листья все корни сборщика мусора. Например, начиная с объекта ClassC , на который ссылается корень GC root 2, мы можем проследить все ссылки и получить следующий граф:

Древовидное представление связей относительно объекта ClassC

Древовидное представление связей относительно объекта ClassC

Таким образом мы увидим, что объект ClassC имеет двух корней-владельцев, оба из которых должны перестать на него ссылаться, прежде чем сборщик мусора сможет его удалить. Чтобы объект ClassC был удален после того, как корень GC root 2 будет установлен в null , должна быть разорвана любая из промежуточных связей между корнем GC root 3 и объектом.

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

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

Пример древовидного представления связей относительно объекта в реальном проекте

Пример древовидного представления связей относительно объекта в реальном проекте

В таком лабиринте может запросто потеряться какой-нибудь объект.

Ограничения сборщика мусора

Неиспользуемые объекты, на которые все еще есть ссылки

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

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

Сборщик мусора предназначен для работы с избыточными ресурсами, то есть когда момент освобождения конкретного ресурса не имеет особого значения. В современных системах в эту категорию попадает память — не важно, когда она освобождается, главное сделать это вовремя, чтобы предотвратить неудачное выделение памяти под новый объект. Есть и ресурсы, которые не попадают в эту категорию, например, дескрипторы файлов должны быть закрыты как можно быстрее, чтобы не вызвать конфликтов между приложениями. Такие ресурсы не могут полностью управляться сборщиком мусора, поэтому .NET предоставляет метод Dispose() вместе с конструкцией using() для объектов, управляющих этими ресурсами. Дефицитные ресурсы, используемые объектом, быстро освобождаются реализацией метода Dispose() вручную (или используя метод using() , что также можно считать ручным освобождением), тогда как гораздо менее критичная память автоматически освобождается сборщиком мусора позже.

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

Фрагментация кучи

Менее известное ограничение — это куча больших объектов (Large Object Heap, LOH), в которой размещаются объекты размером от 85000 байт. Куча больших объектов никогда не уплотняется, соответственно, объекты, которые в ней размещены, никогда не перемещаются, что может привести к преждевременному исчерпанию памяти в программе. Когда одни объекты живут дольше других, в куче образуются так называемые дыры — это называется фрагментацией. Проблема возникает, когда программа запрашивает большой блок памяти, но куча стала настолько фрагментированной, что в ней нет ни одной непрерывной области, достаточно большой, чтобы вместить его. Исключение OutOfMemoryException , вызванное фрагментацией, обычно происходит, когда программа имеет много свободной памяти, но из-за фрагментации не может разместить в ней новый объект.

Другим симптомом фрагментации является то, что .NET-приложению приходится держать память, «занятую» пустыми дырами. Это приводит к тому, что при просмотре в диспетчере задач кажется, что приложение использует гораздо больше памяти, чем ему нужно. Именно это часто происходит, когда профилировщик показывает, что выделенные программой объекты используют лишь небольшой объем памяти, а диспетчер задач показывает, что процесс занимает большой объем.

Производительность сборщика мусора

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

Режимы работы сборщика мусора

Сборщик мусора в .NET имеет два основных режима работы: режим рабочей станции и режим сервера, а также два подрежима: параллельный и непараллельный. Параллельный режим рабочей станции используется в настольных приложениях, а режим сервера — в серверных, например, в ASP.NET.

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

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

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

Поколения сборщика мусора

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

Лучше всего это работает, если .NET может самостоятельно выбирать время сборки мусора. Вызывая GC.Collect() вручную, вы нарушаете эффективность процесса, поскольку это часто приводит к преждевременному устареванию новых объектов, что увеличивает вероятность дорогостоящей полной сборки мусора в ближайшем будущем.

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

Существует простой способ избежать этой проблемы — реализуйте интерфейс IDisposable на финализируемых классах, перенесите необходимые для финализации объекта действия в метод Dispose() , в конце которого вызовите GC.SuppressFinalize() . Финализатор затем может быть модифицирован так, чтобы в нем вызывался метод Dispose() . GC.SuppressFinalize() сообщает сборщику мусора, что объект больше не нуждается в финализации и может быть немедленно удален, в результате чего память будет освобождена гораздо быстрее.

Заключение

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

Примечание переводчика

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

Тем же, кто прочитав статью заинтересовался этой темой, я могу посоветовать ставшую уже классикой в мире .NET книгу Джеффри Рихтера «CLR via C#», в которой вы найдете не только гораздо более подробное описание процесса сборки мусора в .NET, но и массу другой полезной информации.

Основы сборки мусора

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

В этой статье описаны основные понятия сборки мусора.

Преимущества

Использование сборщика мусора обеспечивает следующие преимущества:

Разработчикам не нужно освобождать память вручную.

Эффективно выделяет память для объектов в управляемой куче.

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

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

Основы работы с памятью

В следующем списке перечислены важные понятия памяти среды CLR.

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

По умолчанию на 32-разрядных компьютерах каждому процессу выделяется 2 Гбайт виртуального адресного пространства в пользовательском режиме.

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

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

Виртуальная память может находиться в трех состояниях.

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

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

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

Выделение памяти

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

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

Освобождение памяти

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

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

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

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

Условия для сборки мусора

Сборка мусора возникает при выполнении одного из следующих условий:

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

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

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

Управляемая куча

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

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

Для резервирования памяти сборщик мусора вызывает функцию Windows VirtualAlloc и резервирует для управляемых приложений по одному сегменту памяти за раз. Сборщик мусора также резервирует сегменты по мере необходимости и возвращает операционной системе освобожденные сегменты (очистив их от всех объектов), вызывая функцию Windows VirtualFree.

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

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

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

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

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

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

Поколения

Алгоритм сборки мусора учитывает следующее:

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

Сборка мусора в основном сводится к уничтожению короткоживущих объектов с небольшим временем жизни. Для оптимизации производительности сборщика мусора управляемая куча делится на три поколения: 0, 1 и 2. Следовательно, объекты с большим и небольшим временем жизни обрабатываются отдельно. Сборщик мусора хранит новые объекты в поколении 0. Уровень объектов, созданных на раннем этапе работы приложения и оставшихся после сборок мусора, повышается, и они сохраняются в поколении 1 и 2. Так как сжать часть управляемой кучи быстрее, чем всю кучу, эта схема позволяет сборщику мусора освобождать память в определенном поколении, а не для всей кучи при каждой сборке мусора.

Поколение 0. Это самое молодое поколение содержит короткоживущие объекты. Примером короткоживущего объекта является временная переменная. Сборка мусора чаще всего выполняется в этом поколении.

Вновь распределенные объекты образуют новое поколение объектов и неявно являются сборками поколения 0. Однако если это большие объекты, то они попадают в кучу больших объектов, которая иногда называется поколением 3. Поколение 3 — это физическое поколение, которое логически собирается как часть поколения 2.

Большинство объектов уничтожается при сборке мусора для поколения 0 и не доживает до следующего поколения.

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

Поколение 1. Это поколение содержит коротко живущие объекты и служит буфером между короткоживущими и долгоживущими объектами.

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

Если сборка поколения 0 не освобождает достаточно памяти, чтобы приложение могло создать новый объект, сборщик мусора может выполнить сборку мусора поколения 1, а затем поколения 2. Объекты в поколении 1, оставшиеся после сборок, продвигаются в поколение 2.

Поколение 2. Это поколение содержит долгоживущие объекты. Примером долгоживущих объектов служит объект в серверном приложении, содержащий статические данные, которые существуют в течение длительности процесса.

Объекты в поколении 2, оставшиеся после сборки, находятся там до тех пор, пока они не станут недостижимыми в следующей сборке.

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

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

Выживание и переходы

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

  • Объекты, оставшиеся после сборки мусора поколения 0, подвигаются в поколение 1.
  • Объекты, оставшиеся после сборки мусора поколения 1, подвигаются в поколение 2.
  • Объекты, оставшиеся после сборки мусора поколения 2, остаются в поколении 2.

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

Эфемерные поколения и сегменты

Так как объекты в поколениях 0 и 1 являются короткоживущими, эти поколения называются эфемерными поколениями.

Эфемерные поколения выделяются в сегменте памяти, который называется эфемерным сегментом. Каждый новый сегмент, полученный сборщиком мусора, становится новым эфемерным сегментом и содержит объекты, пережившие сборку мусора для поколения 0. Старый эфемерный сегмент становится новым сегментом поколения 2.

Размер эфемерного сегмента зависит от того, является ли система 32- или 64-разрядной, и от типа сборщика мусора (сборка мусора рабочей станции или сервера). В следующей таблице показаны размеры эфемерного сегмента по умолчанию.

Сборка мусора рабочей станции и сервера 32-разрядная версия 64-разрядная версия
Сборщик мусора рабочей станции 16 МБ 256 МБ
Сборщик мусора сервера 64 МБ 4 Гбайт
Сборка мусора сервера с 4 логическими > ЦП 32 МБ 2 ГБ
Сборка мусора сервера с 8 логическими > ЦП 16 МБ 1 ГБ

Этот эфемерный сегмент может содержать объекты поколения 2. Объекты поколения 2 могут использовать несколько сегментов (столько, сколько требуется процессу и сколько разрешает память).

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

Процесс сборки мусора

Сборка мусора состоит из следующих этапов:

Этап маркировки, выполняющий поиск всех используемых объектов и составляющий их перечень.

Этап перемещения, обновляющий ссылки на сжимаемые объекты.

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

Так как сборки поколения 2 могут занимать несколько сегментов, объекты, перешедшие в поколение 2, могут быть перемещены в более старый сегмент. Выжившие объекты поколений 1 и 2 могут быть перемещены в другой сегмент, так как они перешли в поколение 2.

Как правило, куча больших объектов (LOH) не сжимается, так как копирование больших объектов приводит к снижению производительности. Однако в .NET Core и в .NET Framework 4.5.1 и более поздних версиях можно использовать свойство GCSettings.LargeObjectHeapCompactionMode для сжатия большой кучи объектов по требованию. Кроме того, куча больших объектов автоматически сжимается при установке жесткого ограничения с помощью одного из следующих параметров:

  • Предельный объем памяти для контейнера.
  • Параметры конфигурации среды выполнения GCHeapHardLimit или GCHeapHardLimitPercent .

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

Корни стека. Переменные стека, предоставленные JIT-компилятором и средством обхода стека. JIT-оптимизация позволяет уменьшить или увеличить области кода, в которых переменные стека сообщаются сборщику мусора.

Дескрипторы сборки мусора. Дескрипторы, которые указывают на управляемые объекты и которые могут быть выделены пользовательским кодом или средой CLR.

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

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

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

When a thread triggers a Garbage Collection

Неуправляемые ресурсы

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

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

Как очистить папку Temp

Как очистить папку Temp

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

Такие действия в отношении нашего компьютера не могут проходить без следа: временные файлы «собираются» в нем постоянно и перегружают и без того забитую до верху папку Temp.

А так как все мы знаем, что свободное пространство — один из залогов успеха эффективной работы ПК, то перегруженная «мусором» папка Temp, соответственно, постоянно замедляет операционные процессы. Поэтомы мы расмотрим вопрос — как очистить папку Temp?

Этап первый: поиск папок Temp

Подобных файловых хранилищ в ПК может быть несколько, но чаще папок Temp у нас всего две. Одна расположена в папке Windows, а именно: в системном разделе ПК, вторую же можно без труда отыскать в профиле пользователя, включив для этого скрытые отображения папок. Так, в системе Windows 7 необходимо проследовать путем: Диск С: Папка Users — Имя пользователя — AppData — Local

Если по какой-то причине вы не нашли здесь папку Temp, обратитесь за помощью с верному другу «Поиску» и команде «Выполнить». В появившемся окне просто введите команду %TEMP%, и она автоматически откроется перед вашими глазами.

Этап второй: делаем ее более удобной

Если возникла необходимость сделать работу с папками удобнее, то обе Temp с хранящимися в них временными файлами можно объединить в одну или создать совершенно новую в другом удобном для вас месте. Заходите в меню «Пуск», нажимаете на «Компьютер» и открываете настройки системы.

Как очистить папку Temp
Как очистить папку Temp

Далее выбирайте «Дополнительные параметры». Внизу списка вы увидите «Переменные среды».

Как очистить папку Temp

В открывшемся окне измените путь к введенным адресам TEMP и TMP на созданную или выбранную папку. Сделать это просто: левой клавишей мыши нажмите на каждую переменную, затем примените функцию «Изменить» и наберите новый путь к папке.

Как очистить папку Temp

Подтвердите выбор клавишей «ОК». В итоге вы получите одну папку, хранящую временные файлы в удобном для вас месте.

Я рекомендую создать папку с именем «Temp» в корне диска «С» и указать ее в качестве TEMP и TMP.

Как очистить папку Temp

Этап третий: чистка папки Temp без вреда для системы

Если у вас еще возникает вопрос: «А можно ли удалять папку Temp?», спешим вас предупредить, что делать этого категорически нельзя. Зато ее нужно обязательно регулярно очищать, освобождая место для работы на диске.

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

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

Теперь рассмотрим второй способ очистки папки Temp, который не уступает первому ни в эффективности, ни в простоте. Так, в ОС Windows 7 вы найдете специальный сервис под названием «Очистка Диска»: он расположен в служебных программах «Пуска» и позволяет удалять те временные файлы, которые не были задействованы системой более недели.

Для этого нужно выполнить несколько несложных действий.

Сначала перейдите: из меню «Пуск» в «Компьютер».

Правой кнопкой мышки выберите системный диск (чаще всего это диск C:\) и отметьте пункт «Свойства».

Как очистить папку Temp

Далее в возникшей вкладке «Общие» нужно будет нажать на «Очистку диска».

Как очистить папку Temp

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

Как очистить папку Temp

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

Напоминаем, что если вы до этого не объединили папки Temp в одну, то располагаются они либо здесь:

И здесь: диск C:\Users\Имя учетной записи\AppData\Local\Temp

Есть и иной способ найти папки Temp. Нажмите горячие клавиши «Win+R», откройте окошко «Выполнить», введите команду «%TEMP%» и нажмите Ok. Откроется папка C:\Users\Имя учетной записи\AppData\Local\Temp

Есть и еще один вариант, позволяющий очистить папку Temp.

Заходите в блокнот и пишете там следующую команду: rmdir /s /q %temp% Сохраняете документ под каким-либо названием. К примеру clean.bat

Как очистить папку Temp
Как очистить папку Temp

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

Теперь временные файлы не будут засорять системный диск «С» и мешать его работе. А мы этого, собственно, и добивались, и Вам не придеться вручную чистить папки Temp

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

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