Информация о полезной статье

.NET: Компоненты и процесс компиляции

Оглавление


Полная схема процесса

┌─────────────────────────────────────────────────────────────────┐
│              ЭТАП 0: НАПИСАНИЕ КОДА (Development)               │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Development                                                    │
│      │                                                          │
│      ├─[BCL]─────────> Использует библиотеки классов            │
│      │                                                          │
│      └─[DLR]─────────> Обрабатывает dynamic типы (если есть)    │
│                                                                 │
│  Результат: Source Code (.cs/.vb файлы)                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────────┐
│                    ЭТАП 1: COMPILE TIME (Сборка)                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Source Code                                                    │
│      │                                                          │
│      ├─[C# Compiler]─> Byte Code (CIL)                          │
│      │                                                          │
│      ├─[CTS]─────────> Проверка типов                           │
│      │                                                          │
│      └─[Metadata]─────> Сбор метаданных                         │
│                                                                 │
│  Результат: Assembly (.exe/.dll)                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────────┐
│                    ЭТАП 2: RUNTIME (Исполнение)                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Assembly                                                       │
│      │                                                          │
│      ├─[CLR]─────────> Загружает и управляет выполнением        │
│      │                                                          │
│      ├─[VES]─────────> Загрузка сборки                          │
│      │                                                          │
│      ├─[JIT]──────────> Byte Code → Native Code                 │
│      │                                                          │
│      ├─[Metadata]─────> Управление исполнением                  │
│      │                                                          │
│      └─[CLS]──────────> Гарантия совместимости языков           │
│                                                                 │
│  Результат: Выполнение программы (Process)                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Этапы процесса компиляции и исполнения

0) Написание кода (Development)

  • BCL / .NET Libraries: Предоставляет библиотеки классов для разработки
  • DLR: Обрабатывает динамические типы (dynamic), если они используются
  • Результат: Source Code (.cs/.vb файлы)

1) Во время сборки (COMPILE TIME)

  • C# Compiler / VB.Net Compiler: Преобразует Source code в Byte code (CIL)
  • CTS: Обеспечивает согласованность типов данных в Byte code
  • Metadata: Собираются и включаются в сборку, содержащую информацию о структуре кода и типах
  • Результат: Assembly (.exe/.dll)

2) Во время исполнения (RUNTIME)

  • CLR: Загружает и управляет выполнением Assembly
  • VES: Загружает сборку в память
  • JIT: Компилирует Byte code в Native code, оптимизированный под конкретную платформу
  • Metadata: Используются для управления исполнением кода
  • CLS: Гарантирует, что код, написанный на разных языках, может взаимодействовать в рамках .NET
  • Результат: Выполнение программы (Process)

Примечание: FCL используется в .NET Framework вместо BCL


.NET Platform

.NET Platform состоит из большего числа компонентов, на данном этапе было важно только .NET Runtime

┌──────────────────────────────────────┐
│              .NET Platform           │
├──────────────────────────────────────┤
│  ┌────────────┐   ┌──────────────┐   │
│  │ .NET SDK   │   │ .NET Runtime │   │
│  └────────────┘   └──────────────┘   │
└──────────────────────────────────────┘

.NET SDK [Software Development Kit]

Набор инструментов для разработки, компиляции и сборки .NET приложений.

  • Включает компиляторы (Roslyn), инструменты сборки (MSBuild)
  • Предоставляет CLI инструменты (dotnet команды)
  • Содержит библиотеки и шаблоны проектов
  • Используется на этапе разработки и компиляции

.NET Runtime

Среда выполнения для .NET приложений, обеспечивает выполнение скомпилированного кода.

  • Загружает и выполняет .NET приложения
  • Управляет памятью, безопасностью, типами
  • Предоставляет различные реализации выполнения

Компоненты .NET Runtime:

  • CoreCLR [Core Common Language Runtime]
  • BCL [Base Class Library]
  • DLR [Dynamic Language Runtime]
  • Native AOT [Ahead-of-Time Compilation]

Компоненты .NET

.NET Runtime состоит из 3 основных компонентов:

┌─────────────────────────────────────────────────┐
│         NET Runtime Components                  │
├─────────────────────────────────────────────────┤
│                                                 │
│  ┌─────────┐  ┌──────┐  ┌──────┐                │
│  │ CoreCLR │  │ BCL  │  │ DLR  │                │
│  └─────────┘  └──────┘  └──────┘                │
│                                                 │
└─────────────────────────────────────────────────┘

CoreCLR [Core Common Language Runtime]

Общеязыковая исполняющая среда, управляет выполнением .NET приложений.

  • Работает с Byte code и Native code
  • Принимает Byte code (IL) из Assembly
  • Компилирует его в Native code через JIT компилятор
  • Управляет выполнением Native code на протяжении всего жизненного цикла программы

Примечание: CLR — термин для .NET Framework.

BCL [Base Class Library]

Библиотеки классов, предоставляющие готовые API для разработки.

  • Используется при написании Source code
  • Предоставляет классы и API для разработки (коллекции, работа с файлами, сеть и т.д.)
  • Используется в Source code на C# или VB.Net через директивы using

Примечание: FCL — термин для .NET Framework. CoreFX для Core.

DLR [Dynamic Language Runtime]

Среда, поддерживающая работу с динамическими типами (dynamic).

  • Работает с Source code, использующим dynamic типы
  • Обрабатывает динамические типы во время выполнения
  • Обеспечивает позднее связывание (late binding) для динамических операций

Native AOT [Ahead-of-Time Compilation]

Ниже, в разделе компиляции.


Код

Код проходит через 3 состояния:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ Source code │ --> │  Byte code  │ --> │ Native code │
│  (C#/VB)    │     │     (IL)    │     │  (Machine)  │
└─────────────┘     └─────────────┘     └─────────────┘

[Source code]

Код написанный разработчиком на одном из поддерживаемых языков (C# или VB.Net), код высокого уровня.

  • Хранится в файлах с расширениями .cs (C#) или .vb (VB.Net)
  • Содержит логику приложения, классы, методы, переменные
  • Использует FCL (Framework Class Library) в .NET Framework или BCL / .NET Libraries (ранее CoreFX) в современном .NET - библиотеки классов для разработки
  • При использовании dynamic типов задействуется DLR (Dynamic Language Runtime)
  • Компилируется компилятором языка (C# Compiler или VB.Net Compiler) в Byte code

[Byte code]

Промежуточный код (IL), скомпилированный из Source code, платформо-независимый формат.

  • Создается с помощью C# Compiler или VB.Net Compiler из Source code
  • Хранится в сборках (Assembly) - файлах .exe или .dll
  • По синтаксису напоминает ассемблер, но не является машинным кодом
  • Содержит метаданные о типах, методах и структуре программы
  • Не может выполняться напрямую процессором, требует компиляции в Native code
  • Обрабатывается CLR / CoreCLR во время выполнения
  • Один и тот же Byte code может выполняться на разных платформах благодаря кроссплатформенной среде выполнения

[Native code]

Машинный код конкретного процессора, который выполняется непосредственно процессором.

  • Генерируется CoreCLR во время выполнения (runtime) из Byte code через JIT компилятор
  • Платформо-зависимый код конкретного процессора (x86, x64, ARM и т.д.)
  • Оптимизирован под конкретную платформу и архитектуру процессора (Windows, Linux, macOS)
  • Выполняется напрямую процессором без дополнительной интерпретации
  • Кэшируется в памяти для повторного использования
  • Управляется CoreCLR на протяжении всего жизненного цикла выполнения

Виды Source code:

  • Managed code — Созданный на базе .NET, под прямым контролем CLR
  • Unmanaged code — Созданный вне .NET, требует явного освобождения памяти

Важно: Unmanaged code требует явного управления ресурсами для избегания утечек памяти.


Эволюция Byte code (IL):

CIL [Common Intermediate Language]

Низкоуровневый / промежуточный язык, по синтаксису напоминает ассемблер.

  • Современное название промежуточного языка (IL)
  • Используется для создания стандарта ECMA-335
  • Является платформо-независимым форматом Byte code

MS IL [Microsoft Intermediate Language]

Старое название языка CIL, использовалось до стандартизации.

  • Историческое название промежуточного языка
  • Переименован в CIL для создания стандарта ECMA-335
  • В настоящее время используется термин CIL

Компиляция и запуск

Процесс компиляции состоит из 2 этапов:

┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│ COMPILE TIME │ --> │   RUNTIME    │ --> │  EXECUTION   │
│              │     │              │     │              │
│ Source Code  │     │   Assembly   │     │   Process    │
└──────────────┘     └──────────────┘     └──────────────┘

COMPILE TIME (Этап компиляции)

Этап сборки, во время которого Source code преобразуется в Byte code и создается Assembly.

  • C# Compiler или VB.Net Compiler компилирует Source code в Byte code (IL)
  • CTS проверяет согласованность типов данных
  • Metadata собираются и включаются в сборку
  • Результат: Assembly (.exe/.dll) с Byte code, метаданными и манифестом

Команды для компиляции:

  • dotnet build - компилирует Source code в Byte code (IL), создает сборки (.dll/.exe)
  • dotnet publish - компилирует и подготавливает приложение для развертывания
  • csc.exe Program.cs - прямая компиляция C# через компилятор (C# Compiler)

RUNTIME (Этап выполнения)

Этап исполнения, во время которого Assembly загружается, Byte code компилируется в Native code и программа выполняется.

  • CLR загружает и управляет выполнением Assembly
  • VES загружает сборку в память
  • JIT [Just-In-Time Compiler] компилирует Byte code в Native code (см. ниже)
  • Metadata используются для управления исполнением
  • CLS гарантирует совместимость языков
  • Результат: Выполнение программы (Process), Native code выполняется процессором

Компилятор, который преобразует Byte code в Native code во время выполнения программы.

  • Работает внутри CLR / CoreCLR во время выполнения (runtime)
  • Компилирует Byte code в Native code "на лету" (just-in-time) по мере необходимости
  • Оптимизирует код под конкретную платформу и архитектуру процессора
  • Кэширует скомпилированный Native code в памяти для повторного использования

Команды для запуска:

  • dotnet run - компилирует (если нужно) и запускает приложение
  • dotnet MyApp.dll - запускает скомпилированную сборку
  • MyApp.exe - прямой запуск исполняемого файла (Windows)
  • mono MyApp.exe - запуск через Mono runtime (кроссплатформенно)

Компиляция в 1 этап: Native AOT [Ahead-of-Time Compilation]

Метод компиляции Source code → Native code заранее, до выполнения программы без промежуточного Byte code.

  • Компилирует Source code напрямую в Native code, минуя этап Byte code
  • Выполняется во время сборки приложения (compile time)
  • Результат: готовый к выполнению Native code без необходимости JIT компиляции

Преимущества:

  • Уменьшает время на старте
  • Увеличивает общую скорость выполнения
  • Меньший размер приложения

Сборка (Assembly)

┌─────────────────────────────────────────────────┐
│              Assembly Components                │
├─────────────────────────────────────────────────┤
│                                                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────────┐   │
│  │ Manifest │  │ Metadata │  │ Byte code(IL)│   │
│  └──────────┘  └──────────┘  └──────────────┘   │
│                                                 │
└─────────────────────────────────────────────────┘

Assembly (Сборка)

Результат процесса компиляции, единица развертывания и версионирования в .NET. Сборка содержит Byte code (IL), метаданные и манифест.

  • Создается в результате компиляции: Source code → [Компилятор] → Byte code → упаковывается в Assembly
  • Сборка может быть исполняемой (.exe) или библиотекой (.dll)
  • Assembly загружается CLR/CoreCLR во время выполнения
  • JIT компилятор преобразует Byte code из Assembly в Native code

Компоненты сборки:

Manifest (Манифест)

Часть сборки, описывает содержание сборки, версию, зависимости и метаданные.

  • Содержит информацию о самой сборке (имя, версия, зависимости)
  • Описывает, какие файлы и ресурсы входят в сборку
  • Используется CLR для разрешения зависимостей и загрузки сборок

Metadata (Метаданные)

Информация о типах, методах, свойствах и структуре программы, хранящаяся в сборке.

  • Описывают все типы и члены, определенные в сборке
  • Собираются во время компиляции и включаются в Assembly
  • Используются во время выполнения для управления исполнением кода
  • Позволяют CLR работать с типами и методами без исходного кода

Byte code (IL) в сборке

См. выше раздел Код[Byte code]


CLI [Common Language Infrastructure]

CLI состоит из 4 компонентов:

┌─────────────────────────────────────────────────┐
│              CLI Components                     │
├─────────────────────────────────────────────────┤
│                                                 │
│  ┌──────┐  ┌──────┐  ┌──────┐  ┌──────────┐     │
│  │ CTS  │  │ CLS  │  │ VES  │  │ Metadata │     │
│  └──────┘  └──────┘  └──────┘  └──────────┘     │
│                                                 │
└─────────────────────────────────────────────────┘

CLI [Common Language Infrastructure]

Стандарт (ECMA-335), который определяет структуру сборок (Assembly), формат метаданных и процесс их выполнения. Обеспечивает единообразие для всех языков .NET.

  • Определяет структуру сборок (Assembly) и формат метаданных
  • Позволяет коду на разных языках взаимодействовать друг с другом
  • Обеспечивает единую инфраструктуру для компиляции и выполнения .NET приложений
  • Реализуется через компоненты: CTS, CLS, VES и Metadata

CTS [Common Type System]

Общая система типов в CLR, обеспечивает совместимость типов.

  • Обеспечивает согласованность типов данных в Byte code во время компиляции
  • Определяет правила для типов, которые должны поддерживать все языки .NET
  • Гарантирует, что типы из разных языков могут взаимодействовать друг с другом

CLS [Common Language Specification]

Минимальный набор правил для всех языков .NET, определяющий совместимость между языками.

  • Гарантирует, что код, написанный на разных языках, может взаимодействовать в рамках .NET
  • Определяет подмножество CTS, которое должны поддерживать все языки .NET
  • Обеспечивает межъязыковую совместимость на уровне компиляции и выполнения

VES [Virtual Execution System]

Загрузка и выполнение программ в среде CLI.

  • Загружает сборку (Assembly) во время выполнения
  • Использует метаданные для управления исполнением кода
  • Обеспечивает виртуальную среду выполнения для .NET приложений
  • Управляет жизненным циклом выполнения программы

Metadata [Метаданные]

Стандарт формата метаданных, определенный в CLI (ECMA-335), который описывает структуру информации о типах, методах и свойствах.

  • Определяет формат хранения метаданных в Assembly (см. раздел Сборка (Assembly))
  • Обеспечивает единообразие метаданных для всех языков .NET
  • Позволяет VES и CLR работать с типами и методами без исходного кода
  • Используется для межъязыкового взаимодействия через CTS и CLS