Мусоровоз. Категории (генерации) ссылок

Страницы работы

Содержание работы

Мусоровоз

За работу с памятью в .NET Framework отвечает система автоматического управления памятью - Garbage Collection (сбор мусора). Этот механизм отслеживает объекты в памяти, которые уже не используются, и освобождает занятую им память. Программист и приложение не могут повлиять на то, когда будет освобождена память. Они только могу указать, что какой-то объект больше не нужен и не используется. В этот момент он помещается в специальный список на уничтожение.

Допустим, что у вас есть следующий код:

class Person

{

public string FirstName { get; set; }

public string LastName { get; set; }

// другие методы, свойства и что-нибудь еще

}

class OtherClass

{

void MyMethod

{

Person person = new Person();

// Здесь идет манипуляция с данными

// класса Person

}

}

В этом примере объявлен класс Person, который содержит какие-то свойства и методы. В классе OtherClass есть метод MyMethod, внутри которого происходит инициализация объекта класса Person. Есть инициализация, возможно, есть и код использования объекта, но вот кода уничтожения объекта нет. А ведь каждый объект - это память в куче, которая лимитируется ресурсами компьютера. Если ее не чистить, то может произойти ситуация, когда памяти больше не станет и система просто напросто рухнет.

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

На платформе Win32, в таких языках как С/С++ или Delphi мы должны были явно выделять память и явно ее уничтожать. Сейчас уничтожение больше не нужно, благодаря сборщику мусора. Это утверждение действительно только для .NET платформы, а в Win32 приложениях сборщик мусора не работает. Там все по старинке.

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

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

Сразу же скажу, что сборка мусора идет не только в платформе .NET, но и для типов данных .NET. Платформа достаточно универсальна и вы можете без проблем обращаться к системе Windows (Win32 API или даже 64) напрямую и запросить себе кусочек системной памяти. Если вы запросили этот лакомый кусочек в обход платформы, то платформа .NET не сможет отследить эту память и размер кусочка, поэтому такую память желательно освобождать самостоятельно.

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

class Person

{

public string FirstName { get; set; }

public string LastName { get; set; }

// другие методы, свойства и что-нибудь еще

public Person Father { get; set; }

}

class OtherClass

{

Person mainPerson;

void MyMethod

{

Person person1;

Person person2;

mainPerson = new Person();

mainPerson.Father = new Person();

person1 = mainPerson;

person1.Father = mainPerson.Father;

person2 = mainPerson.Father;

person2.Father = mainPerson;

mainPerson = null;

}

}

Обратите внимание, что у класса Person появилось новое свойство - Father класса Person, в котором мы будем хранить класс отца персоны. Теперь посмотрите на метод MyMethod. У класса есть переменная типа Person и в этом методе объявлено две переменные. При этом, локальные переменные создаются так, чтобы они крест на крест использовали ссылки на mainPerson.

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

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

Категории (генерации) ссылок

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

Не смотря на то, что сборка мусора происходит во время минимальной нагрузки на систему, проверка ссылок занимает немало времени, поэтому хотелось бы, чтобы сборщик мусора работал быстро. Чтобы не проверять все ссылки сборщик мусора делит их на три категории (генерации):

Похожие материалы

Информация о работе