Язык программирования C#9 и платформа .NET5
Классы, объекты и ссылки
Прежде чем приступить к исследованию основных тем главы, важно дополнительно прояснить отличие между классами, объектами и ссылочными переменными. Вспомните, что класс — всего лишь модель, которая описывает то, как экземпляр такого типа будет выглядеть и вести себя в памяти. Разумеется, классы определяются внутри файлов кода (которым по соглашению назначается расширение
). Взгляните на следующий простой класс*.cs, определенный в новом проекте консольного приложения C# по имениCar:SimpleGCnamespace SimpleGC{// Car.cspublic class Car{public int CurrentSpeed {get; set;}public string PetName {get; set;}public Car(){}public Car(string name, int speed){PetName = name;CurrentSpeed = speed;}public override string ToString()=> $"{PetName} is going {CurrentSpeed} MPH";}}}После того как класс определен, в памяти можно размещать любое количество его объектов, применяя ключевое слово new языка С#. Однако следует иметь в виду, что ключевое слово
возвращает ссылку на объект в куче, а не действительный объект. Если ссылочная переменная объявляется как локальная переменная в области действия метода, то она сохраняется в стеке для дальнейшего использования внутри приложения. Для доступа к членам объекта в отношении сохраненной ссылки необходимо применять операцию точки С#:newusing 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:Carstatic void MakeACar(){// Если myCar - единственная ссылка на объект Car, то после// завершения этого метода объект Car *может* быть уничтожен.Car myCar = new Car();}Обратите внимание, что ссылка на объект
была создана непосредственно внутри методаCar(myCar)и не передавалась за пределы определяющей области видимости (через возвращаемое значение или параметрMakeACar()). Таким образом, после завершения данного метода ссылкаref/outоказывается недостижимой, и объектmyCarтеперь является кандидатом на удаление сборщиком мусора. Тем не менее, важно понимать, что восстановление занимаемой этим объектом памяти немедленно после завершения методаCarгарантировать нельзя. В данный момент можно предполагать лишь то, что когда исполняющая среда инициирует следующую сборку мусора, объектMakeACar()может быть безопасно уничтожен.myCarКак вы наверняка сочтете, программирование в среде со сборкой мусора значительно облегчает разработку приложений. И напротив, программистам на языке C++ хорошо известно, что если они не позаботятся о ручном удалении размещенных в куче объектов, тогда утечки памяти не заставят себя долго ждать. На самом деле отслеживание утечек памяти — один из требующих самых больших затрат времени (и утомительных) аспектов программирования в неуправляемых средах. За счет того, что сборщику мусора разрешено взять на себя заботу об уничтожении объектов, обязанности по управлению памятью перекладываются с программистов на исполняющую среду.
Код CIL для ключевого слова new
Когда компилятор C# сталкивается с ключевым словом new, он вставляет в реализацию метода инструкцию
языка CIL. Если вы скомпилируете текущий пример кода и заглянете в полученную сборку с помощью утилитыnewobj, то найдете внутри методаildasm.ехеследующие операторы CIL:MakeACar().method assembly hidebysig staticvoid '<<Main>$>g__MakeACar|0_0'() cil managed{// Code size 8 (0x8)
