Пропоную не стандартний опитувальник .Net

Пропоную не зовсім стандартний опитування по платформі .Net. Спойлерами розкрито відповіді на питання, але все-таки прошу спочатку самим відповісти на опитувальник, після чого йти і дивитися відповіді :)

Коли викликається статичний метод, то JIT...JIT компілює виклик проксі-методу, який робить безумовний перехід на компілятор необхідного і той замінює адресу переходу в проксі на нове тіло методу. Це робиться з декількох причин.

Спочатку, коли методи компілюються, всі точки виклику інших методів вказують не на скомпільований тіло, а на шматочок асемблерного коду фіксованої довжини і містить одні й ті ж інструкції для будь-якого методу. По суті змінюється тільки адресу, на який відбувається jmp. До того як метод скомпільовано, адреса вказує на компілятор цього методу (бо при першому виклику відбувається компіляція). Далі, коли компіляція закінчена, аргумент команди jmp змінюється з адреси компілятора на адресу цільового, вже скомпільованого методу. Плюси очевидні: т. к. проксі — містить одне і ті ж інструкції, то групу методів можна розглядати як таблицю з двома полями: Код і Адреса Переходу з однієї сторони і не міняти адреси в інструкції виклику методу — з іншого.

Що відбувається при кастингу до класуКастинг вниз — не відбувається нічого, кастинг вгору — для початку перевіряється можливість кастингу і робота з об'єктом буде йти по тій же таблиці віртуальних методів, що і раніше

Кастинг до типу — синтаксичний цукор мови, який не має майже нічого спільного на рівні будови об'єкта в пам'яті. Оскільки об'єкт складається з полів + SyncBlockIndex + MethodsTablePtr, де MethodsTablePtr відповідає за вказівник на опис типу об'єкта, то при приміщенні покажчика на об'єкт в змінну іншого типу з об'єктом не відбувається нічого (тип об'єкта не змінюється). Викликається доп перевірка при кастингу вгору, т. к. на етапі компіляції заздалегідь не відомо, що вгорі, які типи. Необхідно перевірити. Перевірка здійснюється через відхід у таблицю методів і прохід по ланцюжку покажчиків ParentClassMethodsTable, поки не зустрінеться або Object (тоді кастинг не можливий) або поки не зустрінемо покажчик, рівний тому, який ми шукаємо. Як здійснюється виклик віртуального методу, добре описано тут: Wiki

Що відбувається при кастингу до інтерфейсуУ таблиці типів існує посилання на словник інтерфейсів і для перевірки можливості кастингу треба обійти її всю. За базовим типам йти не треба, оскільки всі вони також присутні у словнику. Якщо відповідність знайдено, у регістр завантажиться адреса таблиці вірт методів інтерфейсу, а не типу об'єкта

Оскільки інтерфейси можуть з'явитися в типі прямо посередині спадкування як в одному типі, так і в іншому, для них загальна схема з таблицями віртуальних методів працювати не буде. Замість цього, в таблиці віртуальних методів є посилання на другу таблицю — словник інтерфейсів. По суті, це список посилань на таблиці віртуальних методів кожного з них. При кастингу здійснюється пошук необхідної таблиці методом бінарного пошуку, оскільки пошук здійснюється по рівності вказівника на необхідний (серед списку шукається наявність потрібного нам вказівник на таблицю вірт методів). Якщо він знайдений, в регістр завантажується покажчик на цю таблицю і далі виклик методу йде через неї (при цьому таблиця містить адреси методів у класі. Тому для кожної імплементації інтерфейсу список методів присутня в таблицях всіх класів, які імплементують інтерфейс, а також всіх спадкоємців класів і інтерфейсів)

У чому різниця між Implicit і Explicit інтерфейсами?І ті і інші виділені в словник інтерфейсів, однак Implicit методи не знаходяться в таблиці віртуальних методів класу, тільки в словнику інтерфейсів

І дійсно, оскільки методи implicit інтерфейсів є частиною ієрархії успадкування класу та можуть бути викликані окремо від кастингу до інтерфейсу, вони повинні бути присутніми в таблиці віртуальних методів класу. Однак, є ще і Explicit реалізації, коли методи відокремлені від класу. Такі методи не присутні в таблиці віртуальних методів класу. Однак для обох випадків ми маємо право кастить до інтерфейсу і працювати через нього. А це значить що у картці інтерфейсів обох типів вони будуть присутні, причому разом з усіма базовими типами — інтерфейсами.

Потоки .Netє платформеними потоками MS Windows, тому ціна перемикання між потоками дорівнює загальній ціні Windows

Тут, загалом, без коментарів. GC не може встрявати у загальний процес обслуговування багатопотокового коду. Додатка .Net працюють як звичайні програми Windows

Generic типиJIT імплементує ніяк не пов'язані між собою класи під кожен параметр типу

Оскільки JIT не може нічого знати про логікою програми, він не може будувати доводів що
IEnumerable<object> a = new List < int>() 
має якось працювати. тому імплементація під кожен конкретний набір generic аргументів складений окремий код.

Як відбувається виклик примірникових методів — thisthis — перший параметр методу, який для цілей синтаксичного цукру не показується

Якщо уявити собі виклик методу, то на рівні процесора він буде відбуватися по нотації fastcall: перші два параметри методу підуть в регістри, а решта — в стек. якщо нічого додатково не передавати, то вийде що всередині методу ми поняття не будемо мати, для якого об'єкта нас викликали. щоб виправити ситуацію, ми першим параметром завжди передаємо this, а в мові програмування (наприклад, C#) його просто не показуємо, ввівши локальну змінну this, яка присутня завжди, незалежно від бажання програміста. Це і є насправді перший параметр методу.

Value і Reference типи. В чому різниця?Value типи лежать і в стеку і в купі, а Reference — тільки в купі. Відрізняються тим, що value — передаються за значенням, а Reference — за посиланням

Величезний відсоток розробників на співбесідах говорять перший варіант відповіді. Причому насправді він їх не влаштовує, оскільки якщо Value тип є полем класу, в робочому стеку його значення перебувати ну ніяк не може, оскільки при виході з методу, який його створив фрейм, який його містить перестав би бути валідним з правильними даними. Поле класу (навіть якщо це Value тип) завжди знаходиться в купі. Різниця між Value і Ref типами в тому, що при копіюванні у Ref типів посилання копіюється, а у Value — повністю вся структура. Друга відмінність: у незабокшенных Value типів відсутнє поле MethodsTable і SyncBlockIndex.

Де лежать статичні змінні?Лежать у внутрішніх масивах і звернення йде за посиланням на масив + індексом
Це просто сакральне знання. Просто зроблено так і все.

Як викликаються віртуальні методи?JIT створює для типу таблицю віртуальних методів, через яку йде виклик з заздалегідь підрахованим індексом
При спадкуванні та наявності віртуальних методів виходить так: від класу до класу вони можуть тільки додаватися в наявності, не пропадаючи в нікуди. причому в кожному наступному класі гарантовано будуть присутні всі методи всіх базових. З однією відмінністю — при спадкуванні метод можна перевизначити. Тому при побудові таблиці методів для якогось класу, методи базового класу повинні перебувати за тим же індексами, що і в таблиці базового класу. Якщо метод не перевизначений, то й адресу тіла методу в таблиці буде співпадати з адресою цього методу в таблиці базового класу. Якщо метод перевизначений, то значення буде іншим. Після всіх методів базових класів будуть перебувати методи тче класу. А сам виклик буде відбуватися так:
  • Завантажити адресу таблиці вірт методів.
  • Зміститися до початку списку методів
  • взяти адреса методу за індексом (наприклад) 1
  • Викликати його.
Причому оскільки при спадкуванні на цьому місці завжди буде знаходитися метод ToString(), то навіть перевизначаючи його спадкоємців, буде викликаний саме метод ToString(), тільки не базового класу, а спадкоємця.


Коли викликається статичний метод, то:

/>
/>


<input type=«radio» id=«vv64667»
class=«radio js-field-data»
name=«variant[]»
value=«64667» />
JIT компілює прямий виклик методу
<input type=«radio» id=«vv64669»
class=«radio js-field-data»
name=«variant[]»
value=«64669» />
JIT компілює прямий виклик проксі-методу, який безумовно переходить на викликається спочатку
<input type=«radio» id=«vv64671»
class=«radio js-field-data»
name=«variant[]»
value=«64671» />
JIT компілює виклик проксі-методу, який робить безумовний перехід на компілятор необхідного і той замінює адресу переходу в проксі на нове тіло методу
<input type=«radio» id=«vv64673»
class=«radio js-field-data»
name=«variant[]»
value=«64673» />
JIT компілює виклик компілятора, який при виклику змінює всі точки свого виклику на виклик скомпільованого методу

Проголосувало 3 людини. Утрималося-2 людини.


Якщо відбувається кастинг до типу:

/>
/>

<input type=«radio» id=«vv64675»
class=«radio js-field-data»
name=«variant[]»
value=«64675» />
Кастинг вниз — не відбувається нічого, кастинг вгору — для початку перевіряється можливість кастингу і робота з об'єктом буде йти по тій же таблиці віртуальних методів, що і раніше
<input type=«radio» id=«vv64677»
class=«radio js-field-data»
name=«variant[]»
value=«64677» />
Кастинг вниз — не відбувається нічого, кастинг вгору — для початку перевіряється можливість кастингу і робота з об'єктом буде йти по таблиці віртуальних методів нового типу
<input type=«radio» id=«vv64679»
class=«radio js-field-data»
name=«variant[]»
value=«64679» />
В обох напрямках кастингу спочатку перевірка, після чого робота з об'єктом буде йти без зміни таблиці вірт методів
<input type=«radio» id=«vv64681»
class=«radio js-field-data»
name=«variant[]»
value=«64681» />
В обох напрямках кастингу спочатку перевірка, після чого робота з об'єктом буде йти зі зміною таблиці вірт методів на новий тип

Проголосувало 2 людини. Утрималося-2 людини.


Якщо відбувається кастинг до інтерфейсу:

/>
/>

<input type=«radio» id=«vv64683»
class=«radio js-field-data»
name=«variant[]»
value=«64683» />
Інтерфейс присутній серед базових типів, бо це звичайний виклик вірт методу: нічого робити не треба
<input type=«radio» id=«vv64685»
class=«radio js-field-data»
name=«variant[]»
value=«64685» />
У таблиці типів існує посилання на словник інтерфейсів і для перевірки можливості кастингу треба обійти її всю плюс пройтися по всім базовим типам кожного з них на рівність цільовим типу. Якщо відповідність знайдено, у регістр завантажиться адреса таблиці вірт методів інтерфейсу, а не типу об'єкта
<input type=«radio» id=«vv64687»
class=«radio js-field-data»
name=«variant[]»
value=«64687» />
У таблиці типів існує посилання на словник інтерфейсів і для перевірки можливості кастингу треба обійти її всю плюс пройтися по всім базовим типам кожного з них на рівність цільовим типу. Якщо відповідність знайдено, а регістр завантажиться адреса таблиці вірт методів вихідного об'єкта
<input type=«radio» id=«vv64689»
class=«radio js-field-data»
name=«variant[]»
value=«64689» />
Є інструкція процесора, яка вирішує що буде викликано, а пам'ять вибудовується таким чином, щоб процесор все розумів
<input type=«radio» id=«vv64725»
class=«radio js-field-data»
name=«variant[]»
value=«64725» />
У таблиці типів існує посилання на словник інтерфейсів і для перевірки можливості кастингу треба обійти її всю. За базовим типам йти не треба, оскільки всі вони також присутні у словнику. Якщо відповідність знайдено, у регістр завантажиться адреса таблиці вірт методів інтерфейсу, а не типу об'єкта

Проголосував 1 людина. Утрималося-2 людини.


Потоки .Net:

/>
/>

<input type=«radio» id=«vv64691»
class=«radio js-field-data»
name=«variant[]»
value=«64691» />
вони повністю свої, так звані «тонкі» потоки. Тому перемикання контексту між потоками нічого не коштує
<input type=«radio» id=«vv64693»
class=«radio js-field-data»
name=«variant[]»
value=«64693» />
платформеними потоками MS Windows, тому ціна перемикання між потоками дорівнює загальній ціні Windows
<input type=«radio» id=«vv64695»
class=«radio js-field-data»
name=«variant[]»
value=«64695» />
платформеними потоками, однак при перемиканні активного потоку платформа .NET також виконує код, необхідний для GC, тому багатопотокові програми .Net повільніше

Проголосував 1 людина. Утримався 1 людина.


Generic типи (in/out)

/>
/>

<input type=«radio» id=«vv64697»
class=«radio js-field-data»
name=«variant[]»
value=«64697» />
JIT імплементує ніяк не пов'язані між собою класи під кожен параметр типу.
<input type=«radio» id=«vv64699»
class=«radio js-field-data»
name=«variant[]»
value=«64699» />
JIT створює один тип і різні набори методів — всередині нього
<input type=«radio» id=«vv64701»
class=«radio js-field-data»
name=«variant[]»
value=«64701» />
JIT створює один тип і єдиний код під всі варіанти generic параметрів, відмінності тільки в C#

Проголосувало 2 людини. Утримався 1 людина.


Як відбувається виклик примірникових методів

/>
/>

<input type=«radio» id=«vv64703»
class=«radio js-field-data»
name=«variant[]»
value=«64703» />
this — поле класу і зберігається в екземплярі класу
<input type=«radio» id=«vv64705»
class=«radio js-field-data»
name=«variant[]»
value=«64705» />
this — зберігається в спеціальному масиві всередині структур GC і звернення йде за індексом
<input type=«radio» id=«vv64707»
class=«radio js-field-data»
name=«variant[]»
value=«64707» />
this — перший параметр методу, який для цілей синтаксичного цукру не показується

Проголосував 1 людина. Утримався 1 людина.


Value і Reference типи

/>
/>

<input type=«checkbox» id=«vv64709»
class=«checkbox js-field-data»
name=«variant[]»
value=«64709» />
Value типи лежать в стеку, Reference — в купі
<input type=«checkbox» id=«vv64711»
class=«checkbox js-field-data»
name=«variant[]»
value=«64711» />
Value типи лежать і в стеку і в купі, а Reference — тільки в купі. Відрізняються тим, що value — передаються за значенням, а Reference — за посиланням

Проголосувало 3 людини. Утримався 1 людина.


Статичні змінні

/>
/>

<input type=«radio» id=«vv64713»
class=«radio js-field-data»
name=«variant[]»
value=«64713» />
Лежать в obj-MethodsTable->EEClass->storage і звернення йде кожен раз через весь ланцюжок, т. к. GC може рухати будь-яку зі структур в пам'яті
<input type=«radio» id=«vv64715»
class=«radio js-field-data»
name=«variant[]»
value=«64715» />
Лежать у внутрішніх масивах і звернення йде за посиланням на масив + індексу.
<input type=«radio» id=«vv64717»
class=«radio js-field-data»
name=«variant[]»
value=«64717» />
Лежать в окремо виділеній області вірт пам'яті, звернення по прямой ссылке.

Проголосував 1 людина. Утримався 1 людина.


Коли викликається віртуальний метод, то

/>
/>

<input type=«radio» id=«vv64719»
class=«radio js-field-data»
name=«variant[]»
value=«64719» />
JIT створює виклик по прямой ссылке
<input type=«radio» id=«vv64721»
class=«radio js-field-data»
name=«variant[]»
value=«64721» />
JIT створює для типу таблицю віртуальних методів, через яку йде виклик, обчислюючи індекс на льоту
<input type=«radio» id=«vv64723»
class=«radio js-field-data»
name=«variant[]»
value=«64723» />
JIT створює для типу таблицю віртуальних методів, через яку йде виклик з заздалегідь підрахованим індексом

Проголосував 1 людина. Утримався 1 людина.


У чому різниця між Implicit і Explicit інтерфейсами?

/>
/>

<input type=«radio» id=«vv64743»
class=«radio js-field-data»
name=«variant[]»
value=«64743» />
На рівні виклику — ніякої. Все працює через словник інтерфейсів
<input type=«radio» id=«vv64745»
class=«radio js-field-data»
name=«variant[]»
value=«64745» />
Implicit інтерфейси не видно на рівні таблиць вірт методів, і є частиною типу. Explicit видно, т. к. виділені з словника інтерфейсів
<input type=«radio» id=«vv64747»
class=«radio js-field-data»
name=«variant[]»
value=«64747» />
І ті і інші виділені в словник інтерфейсів, однак Implicit методи не знаходяться в таблиці віртуальних методів класу, тільки в словнику інтерфейсів

Ніхто ще не голосував. Утримався 1 людина.


Тільки зареєстровані користувачі можуть брати участь в опитуванні. Увійдіть, будь ласка.


Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.