Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Руководство_по_C#.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
10.01 Mб
Скачать

13.Время жизни объектов

13.1Базовые сведения о времени жизни объектов

Программистам на C# никогда не приходится непосредственно удалять управляемый объект из памяти (в языке C# нет даже ключевого слова вроде delete). Вместо этого объекты .NET размещаются в области памяти, которая называется управляемой кучей (managed heap), откуда они автоматически удаляются сборщиком мусора, когда наступает "определенный момент в будущем".

Давайте проясним различие между классами, объектами и ссылками. Вспомните, что класс представляет собой ни что иное, как схему, которая описывает то, каким образом экземпляр данного типа должен выглядеть и вести себя в памяти. Определяются классы в файлах кода (которым по соглашению назначается расширение *.cs). Для примера создадим новый проект типа Console Application (Консольное приложение) на C# и определим в нем следующий простой класс UserInfo:

using System;

namespace ConsoleApplication1

{

class UserInfo

{

public string Name { get; set; }

public byte Age { get; set; }

public UserInfo() { }

public UserInfo(string Name, byte Age)

{

this.Name = Name;

this.Age = Age;

}

public override string ToString()

{

return String.Format("Имя пользователя: {0} Возраст: {1}",

Name, Age);

}

}

class Program

{

static void Main()

{

// Создание нового объекта UserInfo в управляемой куче

// Возвращаемая ссылка на этот объект user1:

UserInfo User1 = new UserInfo("Alex", 26);

Console.WriteLine(User1.ToString());

Console.ReadLine();

}

public static void MyUser()

{

UserInfo ui = new UserInfo();

}

}

}

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

При создании приложений на C# можно смело полагать, что исполняющая среда .NET будет сама заботиться об управляемой куче без непосредственного вмешательства со стороны программиста. На самом деле "золотое правило" по управлению памятью в .NET звучит просто:

Размещайте объект в управляемой куче с использованием ключевого слова new и забывайте об этом.

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

Как станет ясно со временем, программирование в среде с автоматической сборкой мусора значительно облегчает разработку приложений. Программистам на С++ хорошо известно, что если они специально не позаботятся об удалении размещаемых в куче объектов, вскоре обязательно начнут возникать "утечки памяти". На самом деле отслеживание проблем, связанных с утечкой памяти, является одним из самых длительных (и утомительных) аспектов программирования в неуправляемых средах. Благодаря назначению ответственным за уничтожение объектов сборщика мусора, обязанности по управлению памятью, по сути, сняты с плеч программиста и возложены на CLR-среду.

CIL-код, генерируемый для ключевого слова new

При обнаружении ключевого слова new компилятор C# вставляет в реализацию метода CIL-инструкцию newobj. Если скомпилировать текущий пример кода и заглянуть в полученную сборку с помощью утилиты ildasm.exe, то можно обнаружить внутри метода MyUser() следующие CIL-операторы:

Прежде чем ознакомиться с точными правилами, которые определяют момент, когда объект должен удаляться из управляемой кучи, давайте более подробно рассмотрим роль CIL-инструкции newobj. Для начала важно понять, что управляемая куча представляет собой нечто большее, чем просто случайный фрагмент памяти, к которому CLR получает доступ. Сборщик мусора .NET "убирает" кучу довольно тщательно, причем (при необходимости) даже сжимает пустые блоки памяти с целью оптимизации. Чтобы ему было легче это делать, в управляемой куче поддерживается указатель (обычно называемый указателем на следующий объект или указателем на новый объект), который показывает, где точно будет размещаться следующий объект.

Таким образом, инструкция newobj заставляет CLR-среду выполнить перечисленные ниже ключевые операции:

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

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

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

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

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

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

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