Еще одним достаточно сильным преимуществом платформы .NET является полное снятие вопроса о сборке мусора с программиста. Что имеется в виду. К примеру, вы создаете некоторый класс, а потом по ходу кода создаете объекты этого и других классов. В это время в памяти компьютера каждый раз при создании объектов выделяется некоторая часть этой памяти. Это как в коробку складывать книги – с каждой вновь положенной книгой свободного места в коробке становится все меньше. В какой то момент вся коробка будет заполнена, а вам еще требуется поместить в неё несколько книг…
Так и с памятью. Существует вероятность, что в некоторый момент весь допустимый объем памяти израсходуется. И при попытке создания нового объекта мы получим проблемы в работе приложения.
И самое приятное при программировании под .NET это отсутствие необходимости вручную удалять объекты после их использования. Все это дело платформа .NET выполняет сама.
Ну а при чем здесь понятие «сборки мусора»? Мусором как раз считается та часть данных, которая больше не используется в работе приложения. А служба, которая отвечает за сборку мусора называется GC (garbage collector). GC периодически освобождает память, удаляя объекты, которые уже не будут востребованы приложением — то есть производит сборку мусора.
Реально во время работы вашего приложения, параллельно (в отдельном потоке) работает сборщик мусора. И как только .NET обнаруживает, что управляемая куча данного заполнилась до некоторого предела, она вызывает сборщик мусора. Выполняется проход по всем переменным (объектам), находящимся в контексте исполняемого кода, и проверяет ссылки на объекты, расположенные в области кучи. Любой объект, на который нет ни одной ссылки, помечается кандидатом на удаление.
К примеру, вы создали класс MyClass. После в коде создали экземпляр этого класса используя ключевое слово new.
using System;
class Program
{
static void Main()
{
Myclass myClass = new Myclass("Первый");
myClass = new Myclass("Второй");
}
}
class Myclass
{
String name;
public Myclass(string name)
{
this.name = name;
}
}
В это время в управляемой куче выделилась некоторая область памяти под только что созданный объект, на который мы указали ссылку myClass используя оператор «=». Имеем переменную (ссылку) myClass в стеке и соответствующий ей объект типа MyClass в управляемой куче (рисунок 1).
Рисунок 1. Создание первого объекта
Но что произойдет, если дальше в коде мы создадим еще один объект типа MyClass и ссылку на него поместим в нашу же переменную myClass? Получится вот что. В куче создастся еще один объект. В стеке находится по-прежнему одна переменная myClass, которая уже связана со вторым объектом. Но первый объект продолжает существовать в куче! Другое дело, доступиться к нему мы уже не можем. И не можем потому, что не располагаем ссылками на этот объект (рисунок 2) (конечно, ссылка (переменная) myClass не переместилась по стеку, это только на рисунке для правильного сопоставления новому объекту).
Рисунок 2. Создание второго объекта
Вот сейчас как раз сборщик мусора и обнаружит, что на первый объект в куче нет ссылок. А потому этот бесхожий объект будет выставлен кандидатом на удаление и будет удален при первой же возможности. Следует знать, что хотя сборщик мусора работает постоянно, пока работает ваше приложение, удаление объектов происходит не постоянно и непрерывно, а лишь по мере надобности, зачастую при нехватке памяти. Но вместе с тем, мы не можем точно сказать, когда именно CLR вновь решит освободить память.
В следующей статье мы рассмотрим некоторые детали алгоритма работы сборщика мусора и разберем возможные варианты по ручному управлению освобождения памяти.