Skip to content

Instantly share code, notes, and snippets.

  • Save eterekhin/e6a25489eaa6f8b4aa08595e4a61b520 to your computer and use it in GitHub Desktop.
Save eterekhin/e6a25489eaa6f8b4aa08595e4a61b520 to your computer and use it in GitHub Desktop.
Рихтер.Связь между сборками и пространством имен.Как разные компоненты взаимодействуют во время выполнения.

Связь между сборками и пространством имен

В разных сборках могут быть одинаковые пространства имен, открыв один такой namespace, будут доступны типы из разных сборок

Как разные компоненты взаимодействуют во время выполнения

При исполнении программы у каждого потока есть свой стек, его размер - 1МБ В процессе выполнения программы в этот стек помещаются разлиные значения переменных и полей, например при вызове метода T1:

        public int T()
        {
            var v = "q";
            T1(v);
            return 1;
        }

        private void T1(string q)
        {
            Console.WriteLine(q);
        }

В стеке находятся: ...

  • переменная v
  • аргумент метода T1 q
  • адрес возврата из функции T1 в функцию T

тем самым, когда мы выходим из метода T1 стек становится таким: ...

  • переменная v

Все записи относящиеся к методу T1 из стека извлекаются

Это происходит в стеке, в куче же создаются ссылочные типы и выделяется память под их экземпляры. При первом обращении к типу,нужно создать его представление в куче, таблицу методов, по которой можно определить все методы, которые декларирует тип. Два обязательных элемента у каждого жителя кучи - индекс синхронизации(нужен CLR) и указать на тип. Указатель на тип нужен для определения типов у экземпляров объектов, например у экземпляра класса Employee, будет ссылка на тип Employee(это тоже объект в куче), самое интересное, что у Employee тоже существует ссылка на на объект типа - это тип Type, а у типа Type эта ссылка указывает на самого себя.Также кроме таблицы методов в типе будут находиться все статические члены типа, потому что они определяеются только один раз. Все типы загружаются в момент надобности(обращения к ним), отследить загрузку можно поставиви break point в статическом ctor'e.

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

Также нужно отметить, что вызовы виртуальных/невиртуальных и статических методов в среде CLR различаются, при вызове статических и невиртуальных методов CLR смотрит тип объекта и находит метод в таблице методов объекта типа(если не нашел там, то просмотрит базовый тип объекта, ссылка на него также хранится в куче, далее, при необходимости JIT компилятор преобразует CLR код в машинные команды, и выполняет их

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

В случае невиртуального метода происходит поиск по декларируемому типу переменной, для этого типа происходит поиск по таблице методов, выбирается нужный и вызывается(или JIT компилятор)

Кстати вызов метода GetType возвращает указатель на тип объекта, тип объекта в системе создается лишь один раз => вызов метода GetType на разных экземплярах одного типа возвращает тот же самый объект

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment