Урок 1. Объект и экземпляры. Создание экземпляра по сильной и слабой ссылке

До этого были рассмотрено создание классов (чертежей) и как уже упоминалось до этого: без создания объектов по этому классу (их ещё называют экземплярами класса) использовать их возможности не выйдет, ведь будет происходить попытка обращения к несуществующему объекту.

Для того, что бы создать объект нужно написать:

new MyClass();

Вместо MyClass нужно подставлять тип объекта, экземпляр которого нужно создать.

Ключевое слово new обозначает, что объект нужно разместить на куче (в специальной области памяти, где хранятся ссылочные типы данных). Всего есть два вида куч:

  1. неуправляемая куча – область оперативной памяти, где ОС хранит свои данные, а также все активные приложения. Данные в неуправляемой куче не упорядочены: давно неиспользуемые данные нужно удалять вручную;
  2. управляемая куча – область памяти, которая находится внутри неуправляемой кучи, выделяется для приложений использующих .Net платформу. Данные в управляемой куче упорядочены, за управлением кучей отвечает отдельный механизм принадлежащий платформе .Net – сборщик мусора (Garbage Collector; GC).

Куча – это специальная область памяти, которая выделяется для каждого предложения использующего платформу .Net и в ней хранятся различные ссылочные данные (на эти данные ссылаются переменные в программном коде).

Ссылочными их называют потому, что в стеке, где должно храниться значение переменной, в переменных ссылочных типов (классов, интерфейсов и т.д.) хранятся ссылки на область в куче, где хранится сама переменная.

Ссылочные типы данных – это типы, для которых при переменной данного типа в ней будет храниться ссылка на объект в памяти, а не сам объект. Две переменные ссылочного типа могут ссылаться на один и тот же объект, поэтому операции над одной переменной могут затрагивать объект, на который ссылается другая переменная.

На самом деле пусть и было сказано, что используя эту запись мы создаём объект, но в ООП под объектом зачастую подразумевается нечто иное. Для разбора этого, давайте посмотрим изображение ниже:

1

При конструировании нашего объекта (самого первого для этого типа) в памяти он разбивается на две части:

  1. объект – это участок памяти, в котором хранится всё общее для всех «объектов» одного типа, а именно: описание их поведения (то есть методы) и некие статические члены (статика будет рассматриваться в дальнейшем).
  2. экземпляр – это участок памяти, в котором хранятся данные описывающие определённый «объект» данного типа, также в экземпляре храниться ссылка на объект (на своё поведение).

Примечание: на куче будет существовать только один объект для каждого класса, и все экземпляры этого класса будут ссылаться на него. Это сделано для экономии памяти (ОЗУ не бесконечна), а если бы объект создавался для каждого объекта отдельно, то в памяти было бы достаточно много повторяющееся информации (кол.экземпляров = кол. повторов), поскольку все экземпляры ведут себя одинаково.

Из этого следует, что на самом деле при использовании вот этой записи:

new MyClass();

мы не создавали объект, а создавали экземпляр класса MyClass.

Также нужно сказать о разнице между созданием экземпляра по слабой ссылке и по сильной ссылке:

  • когда экземпляр создаётся, и ссылка на него не записывается в переменную, тогда это создание экземпляра по слабой ссылке. Такое создание экземпляра можно использовать, если экземпляр нужен лишь для вызова определённого метода на нём и в дальнейшем не используется! Например: new MyClass().Method();
  • когда экземпляр создаётся, и ссылка на него записывается в переменную, тогда это создание экземпляра по сильной ссылке. Например:

MyClass instance = new MyClass();

Строку кода выше можно прочитать разными способами, вот 4 самые распространённые варианты:

  1. Создаем экземпляр класса MyClass (по сильной ссылке).
  2. Создаем экземпляр класса MyClass с именем instance.
  3. Инстанцируем класс MyClass.
  4. Создаем переменную с именем instance, типа MyClass и присваиваем ей адрес экземпляра на куче. (instance - является ссылкой на экземпляр класса MyClass построенный на куче)

Инстанцирование (instantiation) — создание экземпляра класса. В отличие от слова «создание», применяется не к объекту, а к классу. То есть, говорят: «создать экземпляр класса или инстанцировать класс».

Бесплатное видео по C# по этой теме

Хорошая статья, но она не раскрыла один из аспектов того что описывала, в части, того что в Объекте содержатся описание статики и методов, что или каким образом происходит вызов метода разных экземпляров если метод фактически один описывающийся в объекте? Если вызвать одновременно один и тот же метод через разные экземпляры? Как проходит исполнение метода? Будет ли наложение передаваемых данных в методе ?

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

Если вызов будет происходить одновременно из двух потоков, то проблемы не будет потому что два потока будет работать с одним и тем же методом, но при этом с разными адресами памяти в которых хранятся экземпляры. Наложений данных не будет - у каждого потока будет свой стек вызова.

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

Да, Вы привели хороший пример с листком бумаги.

Но не понимаю в чем будет наложение, если первому человеку скажут читай строку 5 и второму человеку скажут читай строку 5, с одного и того же листка, они прочтут без каких либо проблем.
Если на листке будет написано - сделай для себя запись (создай переменную), то каждый человек сделает в своей записной книжке для себя пометку (каждый поток сделает для себя локальную переменную).

Если говорить о аналогии с листком бумаги и двумя читателями, то каждый будет читать одно и тоже и у себя в голове держать ту строку, которую он сейчас читает (в случае потоков хранить данные в своих стеках).

Может я не правильно Вас понял или не настолько хорошо понимаю как работает стек вызовов :slight_smile: