
- •Широкоіорматні сканери
- •Об'єктна модель документа (dom)
- •Панель інструментів
- •Керуючі елементи стану
- •Засоби управління
- •Види базових об'єктів в 3ds Max
- •Опис середовища розробки Unity 3d
- •Ide поєднує редактор сцен (в комплексі загального редактора) з редактором ігрових об'єктів і редактор скриптів. Додатково додаються генератори дерев і «террейнів»;
- •Основні поняття та компоненти Uniti3d
- •Інтерфейс Unity3d
- •Опис мови програмування c#
- •Опис платформи .Net Framework
- •Процес завантаження і виконання коду в платформі .Net
- •Бібліотека класів .Net Framework
- •Нові можливості платформи .Net Framework 4.0
- •Виробнича собівартість:
- •Охорона праці
- •Організації робочого місця користувача еом
- •Аналіз шкідливих і небезпечних факторів
- •Мікроклімат робочої зони
- •Захист від шуму та вібрації
- •Виробниче освітлення
- •Випромінювання оптичного спектру
- •Протипожежний захист
- •Розрахунок запобіжника для блоку живлення комп’ютера
Процес завантаження і виконання коду в платформі .Net
При виконанні виконуваного файлу Windows аналізує заголовок ЕХЕ-файлу на предмет необхідного для його роботи адресного простору – 32- або 64-розрядного. Файл із заголовком РЕ32 може виконуватися в адресному просторі будь-якого з вказаних двох типів, а файлу із заголовком РЕ32+ потрібний 64-розрядний простір. Windows також перевіряє інформацію про процесорну архітектуру на предмет сумісності з наявної конфігурацією. 64-розрядні версії Windows підтримують технологію виконання 32-розрядних програм в 64-розрядному середовищі, яке називають WoW64 (Windows On Windows 64). Вона навіть дозволяє виконувати 32-розрядні програми на машині з процесором Itanium за рахунок емуляції команд х86, але за це доводиться розплачуватися зниженням продуктивності.
Після аналізу заголовка ЕХЕ-файлу для з'ясування того, який процес запустити – 32-, 64-розрядний або WoW64, Windows завантажує в адресний простір процесу відповідну (х86, х64 або IA64) версію бібліотеки MSCorEE.dll. У Windows версії х86 однойменна версія MSCorEE.dll зберігається в каталозі C:\Windows\System32. У версіях х64 і IA64 версія х86 бібліотеки знаходиться в каталозі C:\Windows\SysWow64, а 64-розрядна версія MSCorEE.dll (хб4 orIA64) розміщується в каталозі C:\Windows\System32 (це зроблено з міркувань зворотної сумісності).
Далі основний потік процесу викликає визначений в MSCorEE.dll метод, який ініціалізував CLR, завантажує збірку ЕХЕ, а потім її метод точки входу (Main). На цьому процедура запуску керованої програми вважається завершеною.
Як уже згадувалося, керовані модулі містять метадані і код на проміжній мові (IL). IL – не залежна від процесора машинна мова, це мова більш високого рівня порівняно з більшістю інших машинних мов. Вона дозволяє працювати з об'єктами і має команди для створення і ініціалізації об'єктів, виклику віртуальних методів і безпосереднього маніпулювання елементами масивів. У ній навіть є команди генерації і перехоплення виключень для обробки помилок. IL можна розглядати як об'єктно-орієнтовану машинну мову. [11]
Для виконання якого-небудь методу його IL-код повинен бути перетворений в машинні команди. Цим займається JIT-компілятор CLR. Розглянемо приклад:
public void Main()
{
Console.WriteLine("HelloWorld");
}
Безпосередньо перед виконання методу Main середовище CLR знаходить всі типи, на які посилається код Main. При цьому CLR виділяє внутрішні структури даних, використовувані для управління доступом до типів, на які є посилання. У прикладі метод Main посилається на єдиний тип – Console, і CLR виділяє єдину внутрішню структуру. Ця внутрішня структура даних містить по одному запису для кожного методу, визначеного в типі Console. Кожен запис містить адресу, по якій можна знайти реалізацію методу. При ініціалізації цієї структури CLR заносить в кожен запис адресу внутрішньої, недокументованої функції, що міститься в самій CLR. Це функція JIT Compiler.
Функції JIT Compiler відомий метод, що викликається, і тип, в якому він визначений. JIT Compiler шукає в метаданих відповідної збірки IL-код методу, що викликається. Потім JIT Compiler перевіряє і компілює IL-код у власні машинні команди, які зберігаються в динамічно виділеному блоці пам'яті.
Після цього JIT Compiler повертається до внутрішньої структури даних типу і замінює адресу методу, що викликається, адресою блоку пам'яті, що містить готові машинні команди. На завершення JIT Compiler передає управління коду в цьому блоці пам'яті. Цей код – реалізація методу Write Line (тій його версії, що приймає параметр String). З цього методу управління повертається в Main, який продовжує виконання в звичайному порядку.
Потім Main звертається до WriteLine повторно. До цього моменту код WriteLine вже перевірений і скомпільований, так що звернення до блоку пам'яті проводиться, минувши виклик JIT Compiler. Відпрацювавши, метод WriteLine повертає управління Main. Зниження продуктивності спостерігається тільки при першому виклику методу. Все подальші звернення виконуються «на повній швидкості»: повторна верифікація і компіляція не проводяться.
JIT-компілятор зберігає машинні команди в динамічній пам'яті. Це означає, що скомпільований код знищується після закінчення роботи програми. Отже, якщо потім знову викликати програму або якщо одночасно запустити другий її екземпляр (у іншому процесі ОС), JIT-компілятор наново компілюватиме IL-код в машинні команди. [9]
Для більшості програм зниження продуктивності, пов'язане з роботою JIT-компілятора, невелике. Більшість програм раз по раз звертаються до одних і тих же методів. На продуктивності це позначиться тільки раз. До того ж, швидше за все більше часу займає виконання самого методу, а не звернення до нього.
Корисно також знати, що JIT-компілятор CLR оптимізує машинний код аналогічно компілятору некерованого коду C++. Створення оптимізованого коди займає більше часу, але продуктивність його буде набагато вища, ніж неоптимізованого.
Багато авторитетних авторів вважають, що керовані програми можуть працювати продуктивніше некерованих, і тому є маса причин. Узяти хоч би той факт, що перетворюючи IL-код на команди процесора в період виконання, JIT-компілятор має в своєму розпорядженні повніші відомості про середовище виконання, чим компілятор некерованого коду. Нижче перераховані особливості, які дозволяють керованому коду працювати продуктивніше некерованого [11]:
JIT-компілятор може виявити факт виконання програми на Pentium 4 і згенерувати машинний код, що повністю використовує всі переваги особливих команд цього процесора. Некеровані програми зазвичай компілюють з розрахунку на середньостатистичний процесор, уникаючи специфічних команд, які помітно підвищують продуктивність програми на новітніх процесорах.
JIT-компілятор може виявити, що певний вираз на конкретній машині завжди рівний false. Наприклад, подивимося на метод з таким кодом:
if (numberOfCPUs>1)
{
.
}
Тут numberOfCPUs - число процесорів. Код указує JIT-компілятору, що для машини з одним процесором не потрібно генерувати ніяких машинних команд. В цьому випадку машинний код оптимізований для конкретної машини: він коротше і виконується швидше;
CLR може проаналізувати виконання коди і перекомпілювати IL-код в команди процесора під час виконання програми. Перекомпільований код може реорганізовуватися з урахуванням виявлених некоректних прогнозів галуження.
Це лише мала частина аргументів на користь того, що керований код майбутнього виконуватиметься краще сьогоднішнього некерованого. Продуктивність і зараз дуже непогана для більшості програм, а з часом ситуація тільки покращиться. [8]
IL-код і верифікація
IL орієнтований на роботу із стеком, тобто всі його команди поміщають операнди в стек виконання і витягують результати із стека. Оскільки в IL немає команд роботи з регістрами, це спрощує роботу розробникам компіляторів для CLR: не потрібно думати про управління регістрами, та і команд в IL менше (за рахунок відсутності тих же команд роботи з регістрами).
Команди IL не зв'язані і з типами. Наприклад, IL-команда add складає два останні операнди, поміщених в стек; немає окремих 32- і 64-розрядної версій команди. При виконанні add визначає типи операндів в стеку і робить складання.
Головна перевага IL не в тому, що він дозволяє абстрагуватися від конкретного типу процесора, а в надійності і безпеці програм. При компіляції IL в машинний код CLR виконує верифікацію, в процесі якої перевіряється, чи все «безпечно» робить високорівневий IL-код: наприклад, чи потрібне число параметрів передається методу і чи коректні їх типи, чи правильно використовуються повертані методами значення, чи мають всі методи оператори повернення і так далі. Всі необхідні для верифікації відомості про методи і типи є в метаданих керованого модуля. [10]
У Windows у кожного процесу власний віртуальний адресний простір. Окремі адресні простори потрібні тому, що не можна повністю довіряти коду програми. Буває, що програми читає або пише дані за неприпустимою адресою. Розміщення кожного процесу Windows в окремий адресний простір дозволяє добитися надійності: процес не може порушити роботу інших.
Тим часом, верефікувавши керований код, можна бути упевненим, що він не звернеться некоректно до пам'яті і не вплине на код іншої програми. Це означає, що можна виконувати декілька керованих програм в єдиному віртуальному адресному просторі Windows.
Оскільки процеси в Windows вимагають масу ресурсів ОС, наявність безлічі процесів негативно позначається на продуктивності і обмежує доступні ресурси. Зменшення кількості процесів за рахунок запуску декількох програм в одному процесі ОС збільшує продуктивність і знижує потреби в ресурсах, але ніяк не в збиток надійності. Це ще одна перевага керованого коду перед некерованим.
CLR надає можливість виконання безлічі керованих програм в одному процесі ОС. Кожне керована програма пов'язана з доменом програми (AppDomain). За умовчанням кожен керований ЕХЕ-модуль працює у власному, окремому адресному просторі, де є тільки один домен програми. Проте процес, що є хостом CLR (наприклад, Internet Information Services (IIS) або Microsoft SQL Server 2012), може виконувати домени програм в одному процесі ОС. [8]