После того как класс определен, в памяти можно размещать любое количество его объектов, применяя ключевое слово new языка С#. Однако следует иметь в виду, что ключевое слово new возвращает
using System;
using SimpleGC;
Console.WriteLine("***** GC Basics *****");
// Создать новый объект Car в управляемой куче.
// Возвращается ссылка на этот объект (refToMyCar).
Car refToMyCar = new Car("Zippy", 50);
// Операция точки (.) используется для обращения к членам
// объекта с применением ссылочной переменной.
Console.WriteLine(refToMyCar.ToString());
Console.ReadLine();
На заметку! Вспомните из главы 4, что структуры являются типами значений, которые всегда размещаются прямо в стеке и никогда не попадают в управляемую кучу .NET Core. Размещение в куче происходит только при создании экземпляров классов.
Базовые сведения о времени жизни объектов
При создании приложений C# корректно допускать, что исполняющая среда .NET Core позаботится об управляемой куче без вашего прямого вмешательства. В действительности "золотое правило" по управлению памятью в .NET Core выглядит простым.
Правило. Используя ключевое слово new, поместите экземпляр класса в управляемую кучу и забудьте о нем.
После создания объект будет автоматически удален сборщиком мусора, когда необходимость в нем отпадет. Конечно, возникает вполне закономерный вопрос о том, каким образом сборщик мусора выясняет, что объект больше не нужен? Краткий (т.е. неполный) ответ можно сформулировать так: сборщик мусора удаляет объект из кучи, только когда он становится Program метод, который размещает в памяти локальный объект Car:
static void MakeACar()
{
// Если myCar - единственная ссылка на объект Car, то после
// завершения этого метода объект Car *может* быть уничтожен.
Car myCar = new Car();
}
Обратите внимание, что ссылка на объект Car(myCar) была создана непосредственно внутри метода MakeACar() и не передавалась за пределы определяющей области видимости (через возвращаемое значение или параметр ref/out). Таким образом, после завершения данного метода ссылка myCar оказывается недостижимой, и объект Car теперь является кандидатом на удаление сборщиком мусора. Тем не менее, важно понимать, что восстановление занимаемой этим объектом памяти немедленно после завершения метода MakeACar() гарантировать нельзя. В данный момент можно предполагать лишь то, что когда исполняющая среда инициирует следующую сборку мусора, объект myCar может быть безопасно уничтожен.
Как вы наверняка сочтете, программирование в среде со сборкой мусора значительно облегчает разработку приложений. И напротив, программистам на языке C++ хорошо известно, что если они не позаботятся о ручном удалении размещенных в куче объектов, тогда утечки памяти не заставят себя долго ждать. На самом деле отслеживание утечек памяти — один из требующих самых больших затрат времени (и утомительных) аспектов программирования в неуправляемых средах. За счет того, что сборщику мусора разрешено взять на себя заботу об уничтожении объектов, обязанности по управлению памятью перекладываются с программистов на исполняющую среду.
Код CIL для ключевого слова new
Когда компилятор C# сталкивается с ключевым словом new, он вставляет в реализацию метода инструкцию newobj языка CIL. Если вы скомпилируете текущий пример кода и заглянете в полученную сборку с помощью утилиты ildasm.ехе, то найдете внутри метода MakeACar() следующие операторы CIL:
.method assembly hidebysig static
void '<
{
// Code size 8 (0x8)
.maxstack 1
.locals init (class SimpleGC.Car V_0)
IL_0000: nop
IL_0001: newobj instance void SimpleGC.Car::.ctor()
IL_0006: stloc.0
IL_0007: ret