Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Автоматическое управление памятью — это одна из служб, предоставляемых средой CLR во время управляемого выполнения. Сборщик мусора среды CLR управляет выделением и выпуском памяти для приложения. Для разработчиков это означает, что при разработке управляемых приложений вам не нужно писать код для выполнения задач управления памятью. Автоматическое управление памятью может устранить распространенные проблемы, такие как забыли освободить объект и вызвать утечку памяти или попытаться получить доступ к памяти для объекта, который уже освобожден. В этом разделе описывается процесс выделения и освобождения памяти сборщиком мусора.
Выделение памяти
При инициализации нового процесса среда выполнения резервирует для него непрерывную область адресного пространства. Это зарезервированное адресное пространство называется управляемой кучей. Эта управляемая куча содержит указатель адреса, с которого будет выделена память для следующего объекта в куче. Изначально этот указатель устанавливается в базовый адрес управляемой кучи. Все ссылочные типы выделяются в управляемой куче. Когда приложение создает первый ссылочный тип, память для него выделяется, начиная с базового адреса управляемой кучи. Когда приложение создает следующий объект, сборщик мусора выделяет память для него в адресном пространстве сразу после первого объекта. Пока адресное пространство доступно, сборщик мусора продолжает выделять пространство для новых объектов таким образом.
Выделение памяти из управляемой кучи происходит быстрее, чем неуправляемое выделение памяти. Поскольку среда выполнения выделяет память для объекта путем добавления значения к указателю, это почти так же быстро, как выделение памяти из стека. Кроме того, так как новые объекты, выделенные последовательно, хранятся в управляемой куче, приложение может получить доступ к объектам очень быстро.
Освобождение памяти
Механизм оптимизации сборщика мусора определяет наилучшее время для выполнения сбора, основываясь на произведенных выделениях памяти. Когда сборщик мусора выполняет очистку, он освобождает память, выделенную для объектов, которые больше не используются приложением. Он определяет, какие объекты больше не используются путем изучения корней приложения. Каждое приложение имеет набор корней. Каждый корень либо ссылается на объект, находящийся в управляемой куче, либо имеет значение NULL. Корни приложения включают статические поля, локальные переменные и параметры в стеке потока и регистры ЦП. Сборщик мусора имеет доступ к списку активных корней, которые поддерживаются компилятором JIT и средой выполнения. С помощью этого списка он проверяет корни приложения и в процессе создает граф, содержащий все объекты, доступные из корней.
Объекты, которые не находятся в графе, недоступны из корней приложения. Сборщик мусора рассматривает недоступные объекты как мусор и освобождает память, выделенную для них. В процессе очистки сборщик мусора проверяет управляемую кучу, отыскивая блоки адресного пространства, занятые недостижимыми объектами. При обнаружении недостижимого объекта он использует функцию копирования памяти для уплотнения достижимых объектов в памяти, освобождая блоки адресного пространства, выделенные под недостижимые объекты. После уплотнения памяти, занимаемой достижимыми объектами, сборщик мусора вносит необходимые поправки в указатель, чтобы корни приложения указывали на новые расположения объектов. Он также устанавливает указатель управляемой кучи в положение после последнего достижимого объекта. Обратите внимание, что память сжимается только в том случае, если коллекция обнаруживает значительное количество недоступных объектов. Если все объекты в управляемой куче выживут в коллекции, то для сжатия памяти не требуется.
Для повышения производительности среда выполнения выделяет память для больших объектов в отдельной куче. Сборщик мусора автоматически освобождает память, выделенную для больших объектов. Тем не менее, чтобы избежать перемещения больших объектов в памяти, эта память не сжимается.
Поколения и производительность
Для оптимизации производительности сборщика мусора управляемая куча делится на три поколения: 0, 1 и 2. Алгоритм сборки мусора среды выполнения основан на нескольких обобщениях, которые были подтверждены компьютерной отраслью программного обеспечения в процессе экспериментов со схемами сборки мусора. Во-первых, сжимать память для части управляемой кучи быстрее, чем для всей управляемой кучи. Во-вторых, новые объекты будут иметь более короткие сроки существования, и старые объекты будут иметь больше времени существования. Наконец, более новые объекты, как правило, связаны друг с другом и обращаются к приложению примерно в то же время.
Сборщик мусора среды выполнения сохраняет новые объекты в поколении 0. Уровень объектов, созданных на раннем этапе работы приложения и оставшихся после сборок мусора, повышается, и они сохраняются в поколении 1 и 2. Процесс продвижения объектов описан далее в этом разделе. Так как сжимать часть управляемой кучи быстрее, чем всю кучу, эта схема позволяет сборщику мусора освободить память в конкретном поколении, вместо того чтобы освобождать память для всей управляемой кучи каждый раз при выполнении сборки.
В действительности сборщик мусора выполняет сборку мусора при заполнении нулевого поколения. Если приложение пытается создать новый объект, когда поколение 0 полностью занято, сборщик мусора обнаруживает, что в поколении 0 не осталось адресного пространства для выделения под объект. Сборщик мусора выполняет сбор, чтобы попытаться освободить адресное пространство в поколении 0 для объекта. Сборщик мусора начинает проверять объекты в поколении 0, а не все объекты в управляемой куче. Это наиболее эффективный подход, так как новые объекты, как правило, имеют короткое время существования, и ожидается, что многие объекты в поколении 0 больше не будут использоваться приложением при выполнении коллекции. Кроме того, коллекция поколения 0 обычно освобождает достаточно памяти, чтобы приложение продолжало создавать новые объекты.
После того как сборщик мусора выполняет коллекцию поколения 0, он сжимает память для доступных объектов, как описано в разделе "Освобождение памяти " ранее в этом разделе. Затем сборщик мусора продвигает эти объекты и рассматривает эту часть управляемой кучи как поколение 1. Так как объекты, оставшиеся после сборки, обычно склонны к долгой жизни, имеет смысл продвинуть их в поколение более высокого уровня. В результате сборщик мусора не должен заново проверять объекты в поколениях 1 и 2 каждый раз, когда он выполняет сборку поколения 0.
После того как сборщик мусора выполняет свою первую коллекцию объектов поколения 0 и повышает достижимые объекты до поколения 1, он считает оставшуюся часть управляемой кучи как поколение 0. Он продолжает выделять память для новых объектов в поколении 0, пока поколение 0 не будет заполнено, и необходимо выполнить другую коллекцию. На этом этапе подсистема оптимизации сборщика мусора определяет, необходимо ли проверять объекты в более старых поколениях. Например, если коллекция поколения 0 не освобождает достаточно памяти, чтобы приложение успешно завершило попытку создать новый объект, сборщик мусора может выполнить коллекцию поколения 1, а затем поколение 2. Если это не освобождает достаточно памяти, управляющий сборкой мусора может провести сбор поколений 2, 1 и 0. После каждой коллекции сборщик мусора сжимает доступные объекты в поколении 0 и повышает их до поколения 1. Объекты в поколении 1, оставшиеся после сборок, продвигаются в поколение 2. Так как сборщик мусора поддерживает только три поколения, объекты в поколении 2, которые сохраняют коллекцию, остаются в поколении 2, пока они не будут недоступны в будущей коллекции.
Освобождение памяти для неуправляемых ресурсов
Для большинства создаваемых вами объектов можно использовать сборщик мусора для автоматического выполнения необходимых задач управления памятью. Однако для неуправляемых ресурсов требуется явная очистка. Основным типом неуправляемых ресурсов являются объекты, образующие упаковку для ресурсов операционной системы, такие как дескриптор файлов, дескриптор окна или сетевое подключение. Хотя сборщик мусора может отслеживать время существования управляемого объекта, инкапсулирующего неуправляемый ресурс, у него нет конкретных знаний о том, как очистить ресурс. При создании объекта, инкапсулирующего неуправляемый ресурс, рекомендуется предоставить необходимый код для очистки неуправляемого ресурса в общедоступном методе Dispose . Предоставив метод Dispose , вы можете разрешить пользователям объекта явно освободить память после завершения работы с объектом. При использовании объекта, который инкапсулирует неуправляемый ресурс, следует учитывать dispose и вызывать его по мере необходимости. Дополнительные сведения о очистке неуправляемых ресурсов и примере шаблона проектирования для реализации dispose см. в разделе "Сборка мусора".