Глубины виртуализации Windows (часть 3) — виртуальные машины, которые загружаются за секунды: почему WSL2, Windows Sandbox и контейнеры такие лёгкие
· Го Комура · Windows, Виртуализация, WSL2, Windows Sandbox, Контейнеры, Hyper-V
Когда создаёте ВМ Windows в диспетчере Hyper-V, на старт уходят десятки секунд, и она монополизирует несколько гигабайт памяти. Однако на том же ПК ввод wsl возвращает оболочку Linux за несколько секунд, и Windows Sandbox тоже открывает одноразовый рабочий стол за несколько секунд.1
Оба опираются на один гипервизор Windows (часть 1, «Где на самом деле работает ваш Windows?»). В части 2 мы видели, что это основание может создать изоляцию сильнее ядра. Так почему одно тяжёлое, а другое лёгкое?
Вопрос, на который отвечает финальная часть серии, ровно один.
Полные ВМ тяжелы — так почему WSL2 и Windows Sandbox такие лёгкие?
Целевые читатели — разработчики и эксплуатационщики, которые используют WSL2, Windows Sandbox и контейнеры Windows для разработки и проверки и хотят понять их лёгкость и ограничения с механизмов. Предпосылки — Windows 10/11; чтобы пройти раздел про Windows Sandbox, нужна редакция Pro, Enterprise или Education (у Home и Windows Server этой возможности нет). Фоновые знания — понятие разделов из части 1. Сложность — средняя.
1. Сначала вывод
Лёгкая ВМ сохраняет линию изоляции (выделенное ядро и границу гипервизора) и облегчает «копию полной гостевой ОС». Sandbox разделяет сам хостовый Windows; WSL2 заменяет гостя маленьким Linux, собранным под задачу; и в обоих случаях память — не фиксированный резерв, а динамический заём и возврат с хостом.
Источник веса полной ВМ — не сама изоляция, а дублирование. Ещё один образ ОС на диске, ещё одна порция страниц ОС в ОЗУ и ещё одна полная загрузка каждый раз при старте. Лёгкие ВМ срезают это дублирование двумя политиками: «разделять то, что безопасно разделять» (Sandbox) и «если разделить нельзя — пересобрать маленьким» (WSL2).
flowchart TB
accTitle: Три вида разделения, которые держат лёгкие ВМ
accDescr: Образ ОС, который полная ВМ раньше дублировала, срезают разделением в Sandbox и сжатием в WSL2; память, которая по умолчанию — фиксированное выделение (динамическая память — исключение), становится динамическим займом и возвратом с хостом; старт заменяют лёгким ядром и минимальной настройкой; остаётся только граница изоляции
heavy["Полная ВМ: дублирование"] --> d1["Диск: копия образа ОС"]
heavy --> more{"Память или старт?"}
more --> d2["Память: фикс. по умолч."]
more --> d3["Старт: полная загрузка"]
d1 -->|заменено| s1["Разделить(Sandbox)"]
s1 -.-> s1b["или сжать(WSL2)"]
d2 -->|заменено| s2["Динамический заём у хоста"]
d3 -->|заменено| s3["Лёгкое ядро + мин."]
Рис. 1: Скелет ответа на «тот же гипервизор, а легко» в том, что перестали дублировать, а не в том, что перестали изолировать.
Ниже смотрим WSL2, Windows Sandbox и контейнеры в этом порядке и на то, какой вид дублирования каждый из них срезает.
2. Что несёт полная ВМ
Как исходную точку сравнения — вот что несёт традиционная ВМ.
- Независимый образ ОС. Держит каждый файл гостевой ОС внутри виртуального диска. Даже если у хоста тот же Windows, она его не разделяет.
- Грубое выделение памяти. По умолчанию традиционная ВМ выделяет память хоста статическим размером. Механизмы вроде Hyper-V Dynamic Memory могут расти и сжимать выделение в заданном диапазоне, но средств подстроиться под изменение спроса мало.2
- Универсальная полная загрузка. Прошивка, загрузчик и набор служб стартуют в той же последовательности, что на физической машине.
flowchart TB
accTitle: Три нагрузки, которые несёт полная ВМ
accDescr: Полная ВМ несёт независимый образ ОС, выделение памяти, которое по умолчанию статическое, и универсальную полную загрузку, и это проявляется как цена в диске, ОЗУ и времени старта
fullvm["Полная ВМ"] --> b1["Независимый образ ОС"]
fullvm --> more{"Память или загрузка?"}
more --> b2["Статическая память по умолч."]
more --> b3["Универсальная загрузка"]
b1 -.-> c1["Лишний диск на копию"]
b2 -.-> c2["Держит и неиспользуемую ОЗУ"]
b3 -.-> c3["Занимает десятки секунд"]
Рис. 2: Разбор цены полной ВМ платится не за изоляцию, а за универсальность и дублирование.
Это не дефекты; это цена универсальности «в гостя можно положить что угодно». Для сценария вроде запуска старого Linux рядом с Windows Server эта универсальность и есть ценность. Но для сценария вроде «хочу запустить ту же (или заранее заданную) ОС, что у хоста, прямо сейчас, для разработки или проверки» большая часть — лишний багаж. Лёгкие ВМ снимают этот багаж, сужая назначение.
3. WSL2 — служебная ВМ с ядром, собранным под задачу
3.1. Структура: управляемая ВМ и дистрибутивы внутри неё
WSL2 — механизм, который запускает подлинное ядро Linux внутри лёгкой служебной ВМ.3 Есть три пункта.
- Ядро подлинное, но это специализированный продукт. Это ядро Linux, которое Microsoft собирает из ветки Stable, уже настроенное по размеру и производительности под WSL2. На актуальном стандарте, WSL из Microsoft Store, ядро обновляется вместе с самим пакетом WSL и применяется через
wsl --update(на старом встроенном распространении оно приходило через Windows Update).4 Поскольку ядро подлинное, совместимость системных вызовов полная, и инструменты вроде Docker работают как есть. - ВМ за кадром. Созданием, запуском и остановкой ВМ управляет WSL; пользователь просто открывает оболочку. Нет экрана настроек ВМ и нет ощутимого ожидания загрузки.4
- Дистрибутив — контейнер внутри ВМ. Дистрибутивы вроде Ubuntu и Debian работают как изолированные контейнеры внутри одной управляемой ВМ. Они разделяют сетевое пространство имён и ядро, тогда как пространства имён вроде PID, mount и user разделены.3
flowchart TB
accTitle: Архитектура WSL2
accDescr: Хостовый Windows и лёгкая служебная ВМ сидят рядом на гипервизоре; внутри ВМ работает ядро Linux сборки Microsoft; и каждый дистрибутив работает как изолированный контейнер внутри неё
hv["Гипервизор"] --> host["Хостовый Windows"]
hv --> uvm["Лёгкая служебная ВМ"]
uvm --> lk["Ядро Linux (сборка Microsoft; обновление через wsl --update)"]
lk --> u1["Ubuntu (контейнер)"]
lk --> u2["Debian (контейнер)"]
host <-->|"Interop (команды, файлы, сеть)"| uvm
Рис. 3: Ответ на «WSL2 — это ВМ?» — «да, но управляемая, за кадром», и даже если поставить несколько дистрибутивов, ВМ всё равно одна.
В момент, когда вы вводите wsl, задняя сторона выглядит так.
flowchart TB
accTitle: От запуска команды wsl до возврата оболочки за несколько секунд
accDescr: Если служебная ВМ не работает, когда выполняют wsl, стартуют лёгкая ВМ и ядро Linux; если уже работает — переиспользуют; и оболочка возвращается в контейнере дистрибутива
cmd["Запустить wsl"] --> vmq{"Служебная ВМ уже работает?"}
vmq -->|Нет| bootvm["Стартовать лёгкую ВМ и ядро Linux (несколько секунд)"]
vmq -->|Да| reuse["Переиспользовать уже работающую ВМ"]
bootvm --> shell["Оболочка возвращается внутри контейнера"]
reuse --> shell
Рис. 4: Ожидание — только минимальный старт ВМ, и здесь проявляется то, что багаж полной загрузки положили.
3.2. Файловый ввод-вывод: на какую сторону кладёте — другая вещь
Тема, которая всегда всплывает в разговоре о производительности WSL2, — куда кладёте файлы.
- Операции с файлами на стороне Linux (виртуальный диск ext4) быстрые. Потому что ядро Linux говорит со своей файловой системой напрямую, и сообщали об ускорениях до 20× против WSL1 для распаковки tar-архива и 2–5× для
git cloneиnpm install.4 - Операции с файлами на стороне Windows (/mnt/c и подобное) становятся медленными, потому что идут через общий доступ к файлам, который пересекает границу ОС. Производительность межОС-файловой системы — один крупный пункт, где WSL2 хуже WSL1.4
Поэтому правило: «кладите файлы проекта на ту же сторону ОС, что и инструменты, которые ими оперируют».4 Репозиторий, с которым работают инструменты сборки Linux, — на сторону Linux; решение, которое собираете в Visual Studio, — на сторону Windows.
flowchart TB
accTitle: Развилка путей файлового ввода-вывода WSL2
accDescr: Доступ к виртуальному диску ext4 стороны Linux прямой из ядра Linux и поэтому быстрый; доступ к файлам стороны Windows идёт через общий доступ, который пересекает границу ОС, и поэтому медленный
io["Файловые операции внутри WSL2"] --> place{"На какой стороне файл?"}
place -->|"Сторона Linux (home и т. д.)"| ext4["Прямой I/O к вирт. диску ext4"]
place -->|"Сторона Windows (/mnt/c и т. д.)"| p9["Через общий доступ через границу ОС"]
ext4 --> fast["Быстро (примеры до 20× vs. WSL1)"]
p9 --> slow["Склонно быть медленным"]
slow -.-> fix["Исправление: класть файл на ОС, которая его использует"]
Рис. 5: Медленный путь, а не WSL2, поэтому смена того, куда кладёте файлы, часто заставляет проблему производительности исчезнуть.
3.3. Память: растёт, сжимается, но не всегда всё отдаёт
Использование памяти WSL2 (в Диспетчере задач вы видите его как процесс vmmem) — не фиксированный резерв; оно растёт и сжимается с использованием. Память, которую процессы освободили, автоматически возвращается Windows при настройке pageReporting, которая включена по умолчанию.5 Страницы, удерживаемые как файловый кэш, раньше не возвращались Windows, пока ВМ не завершалась.4 В актуальном WSL экспериментальная настройка .wslconfig autoMemoryReclaim (по умолчанию dropCache) изымает кэш автоматически тоже.5 В средах, где эта настройка disabled, или на старом WSL кэш длинного сеанса может оставаться до выхода ВМ и давить на память хоста.
flowchart TB
accTitle: Как память WSL2 растёт, сжимается и возвращается
accDescr: Рост спроса внутри WSL2 поднимает использование памяти ВМ; страницы, освобождённые процессами, возвращаются Windows при pageReporting, которая включена по умолчанию; файловый кэш по умолчанию автоматически изымает autoMemoryReclaim; но на отключённой настройке или старом WSL он остаётся до выхода ВМ, и wsl --shutdown возвращает всё
grow["Спрос на память внутри WSL2 растёт"] --> vm["Использование vmmem растёт"]
vm --> freed{"Эта страница освобождена?"}
freed -->|"Процесс освободил (когда pageReporting вкл.)"| ret["Автоматически возвращено Windows"]
freed -->|Удерживается как файловый кэш| amr["autoMemoryReclaim изымает автоматически (по умолч.)"]
amr -.-> old2["На отключённой настройке или старом WSL остаётся до выхода ВМ"]
old2 --> sd["wsl --shutdown возвращает всё"]
Рис. 6: То, что выглядит как «оно только росло», в основном кэш (и, когда pageReporting выключен, также страницы, освобождённые процессами), поэтому знайте путь возврата, прежде чем решать, что это утечка.
Если нужна явная верхняя граница, %UserProfile%\.wslconfig может управлять общей памятью ВМ, числом ЦП и подкачкой.5
# %UserProfile%\.wslconfig
[wsl2]
memory=8GB
processors=4
swap=2GB
После смены настроек перезапустите ВМ через wsl --shutdown, чтобы они вступили в силу. Это динамическое выделение — «верхняя граница — настройка, фактическое использование следует спросу» — в следующей теме, Windows Sandbox, заходит ещё дальше.
4. Windows Sandbox — повторное использование хостового Windows
4.1. Динамический базовый образ: полный Windows в 500 МБ
Windows Sandbox — одноразовый рабочий стол Windows, изолированный гипервизором. Закроете — всё исчезает; в следующий раз стартует за несколько секунд из чистого состояния.1
Первая загадка — диск. Он может загрузить полный Windows, однако базовый образ Sandbox — лишь около 500 МБ после установки и 30 МБ в сжатом виде при распространении.2 Секрет — динамический базовый образ.
- Большинство файлов ОС неизменяемы, поэтому копии хоста можно разделять как есть.
- Небольшое число изменяемых файлов разделять нельзя, поэтому чистую копию их держат внутри базового образа.
- При старте неизменяемые файлы хоста плюс локальные копии изменяемых файлов сочетают, чтобы собрать полный образ Windows.2
Иными словами, Sandbox ни скачивает, ни хранит копию Windows; он повторно использует Windows, уже установленный на хосте, чтобы стартовать.
flowchart TB
accTitle: Как собирается динамический базовый образ
accDescr: Неизменяемые файлы ОС хостового Windows разделяют; только изменяемые файлы держат как чистую копию в базовом образе; и оба сочетают, чтобы собрать полный образ Windows Sandbox
hostw["Полный Windows хоста"] --> imm["Неизменяемые файлы ОС (большинство)"]
hostw --> mut["Изменяемые файлы ОС (меньшинство)"]
imm -->|Разделяют как есть| img["Загрузочный образ Sandbox"]
mut -->|Держать чистую копию| img
img --> boot["Загружается как полный Windows"]
img -.-> size["Хранить нужно лишь около 500 МБ"]
Рис. 7: Форма отказа от дублирования диска — не «владеть ещё одним Windows», а «собрать его из хостового Windows».
Этот состав и делает возможным следующий жизненный цикл. Что отбрасывают — локальное состояние внутри Sandbox. Если в файле конфигурации .wsb вы сопоставили записываемую папку с хоста, изменения там остаются на хосте.6
flowchart TB
accTitle: Жизненный цикл Windows Sandbox
accDescr: Старт готовит чистый Windows за несколько секунд; после проверки приложения или экспериментов закрываете, и всё состояние внутри Sandbox отбрасывается, так что следующий раз тоже стартует чистым; но изменения в папке хоста, сопоставленной как записываемая, остаются
launch["Старт (несколько секунд)"] --> clean["Чистый Windows"]
clean --> work["Проверка приложения или эксперименты"]
work --> close2["Закрыть"]
close2 --> discard["Отбросить всё состояние внутри Sandbox"]
discard -.-> mapped["Изменения в сопоставленной записываемой папке остаются на хосте"]
discard -->|Следующий старт| launch
Рис. 8: Возможность каждый раз возвращаться к чистому в том, что изменяемая часть — одноразовая копия, и отбросить её — часть проекта.
4.2. Direct map: тот же ntdll.dll — та же физическая страница
Не только диск, но и ОЗУ разделяется. Поскольку Sandbox запускает тот же образ ОС, что хост, применяют приём под названием «direct map», чтобы для двоичных файлов ОС использовать те же страницы физической памяти, что хост. Когда ntdll.dll загружается в память внутри Sandbox, он указывает на ту же физическую страницу, что тот же двоичный файл, уже загруженный на хосте. Не подвергая секреты хоста опасности, это достигает гораздо меньшего следа памяти, чем традиционная ВМ.2
«Разделять одну физическую страницу среди нескольких пользователей» — та же идея, что разделение DLL через объекты разделов, которое мы прослеживали в части 3 серии про память («Объекты разделов и копирование при записи»). Тот механизм был разделением между процессами; Sandbox делает это через границу ВМ.
flowchart TB
accTitle: Разделение физических страниц через direct map
accDescr: Приложение на хосте и приложение внутри Sandbox разделяют одну страницу физической памяти для двоичных файлов ОС вроде ntdll, снижая использование памяти
happ["Приложение на хосте"] --> hva["Вирт. адрес стороны хоста"]
sapp["Приложение внутри Sandbox"] --> sva["Вирт. адрес стороны Sandbox"]
hva --> phys["Та же физ. страница (двоичные файлы ОС вроде ntdll.dll)"]
sva --> phys
phys -.-> save["Не нужно дублировать ОЗУ на объём ОС"]
Рис. 9: Direct map — идея разделения страниц, которую использовали между процессами, применённая через границу ВМ.
4.3. Заём и возврат памяти: больше как процесс, чем как ВМ
Против статического выделения памяти традиционной ВМ технология контейнеров, на которой сидит Sandbox, решает выделение ресурсов динамически в сотрудничестве с хостом. Если хосту не хватает памяти, он может изъять память у контейнера так же, как изымает её у обычного процесса.2 Hyper-V Dynamic Memory тоже растёт и сжимает выделение ВМ в заданном диапазоне, но Sandbox идёт дальше: разница в том, что он занимает и возвращает на том же поле, что управление памятью хоста.
flowchart TB
accTitle: Сотрудничество по памяти между хостом и Sandbox
accDescr: По умолчанию традиционная ВМ — исключительное выделение статического размера с ограниченными средствами подстройки; Sandbox становится целью изъятия в ответ на давление памяти хоста и занимает и возвращает память на том же поле, что обычные процессы
pressure["Давление памяти хоста растёт"] --> from{"Откуда изымать?"}
from --> proc["Working Set обычных процессов"]
from --> sbx["Использование Sandbox (контейнера)"]
proc --> relief["Свободная память обеспечена"]
sbx --> relief
relief -.-> contrast["У традиционной ВМ мало средств подстройки"]
Рис. 10: В займе и возврате памяти Sandbox стоит на стороне процесса, а не ВМ, и отдаёт память, когда хосту трудно.
В части 1 мы говорили «производительность ВМ зависит также от стороны хоста», но с лёгкими ВМ делаем ещё один шаг: само выделение памяти — совместная работа с хостом. Причина, почему Sandbox можно использовать с ощущением «ещё одно приложение», а не «тяжёлый продукт виртуализации», — это сотрудничество.
Конкретная процедура использования Sandbox для проверки бизнес-приложения разобрана в более ранней «Как ускорить проверку приложений с помощью Windows Sandbox». Эта статья — механизм внизу того.
5. Контейнеры — где проводите линию изоляции
5.1. Изоляция процессов и изоляция Hyper-V
У контейнеров Windows два режима изоляции во время выполнения. Образ общий; выбираете флагом при старте.7
- Изоляция процессов: несколько контейнеров разделяют ядро с хостом и изолируются через виртуализацию по пространствам имён файловой системы, реестра, сетевых портов, пространства идентификаторов процессов, пространства имён Object Manager и так далее. По сути тот же подход, что контейнеры Linux.
- Изоляция Hyper-V: каждый контейнер работает внутри сильно оптимизированной ВМ и имеет по сути выделенное ядро. Наличие ВМ ставит изоляцию аппаратного уровня между контейнерами и хостом.7
Изоляцию через пространства имён можно описать как доведённую до конца версию приёма, который мы видели в статье о виртуализации реестра («Перенаправление и виртуализация реестра в Windows»), — «показать другую реальность под тем же API».
flowchart TB
accTitle: Изоляция процессов против изоляции Hyper-V
accDescr: При изоляции процессов контейнеры разделяют ядро с хостом и изолируются через пространства имён; при изоляции Hyper-V у каждого контейнера выделенное ядро внутри оптимизированной ВМ
subgraph pi ["Изоляция процессов"]
c1["Контейнер A"] --> sk1["Ядро, общее с хостом"]
c2["Контейнер B"] --> sk1
end
subgraph hi ["Изоляция Hyper-V"]
c3["Контейнер C"] --> k3["Выделенное ядро (внутри оптим. ВМ)"]
c4["Контейнер D"] --> k4["Выделенное ядро (внутри оптим. ВМ)"]
end
sk1 ~~~ c3
Рис. 11: Даже с одним образом контейнера, проводите ли линию изоляции над ядром или разделяете само ядро — выбор, который делаете при старте.
5.2. Что можно назвать «границей безопасности»
Разница между этими двумя режимами — не только история производительности. Microsoft не считает контейнер с изоляцией процессов устойчивой границей безопасности. Контейнеры, которые поддерживают (с ответом на уязвимости) как границу безопасности, — контейнеры, изолированные гипервизором, и изоляцию Hyper-V стоит выбирать во враждебном мультиарендном сценарии.8
VBS, которую мы видели в части 2, тоже была проектом, который исходит из «ядро можно пробить» и отступает к границе гипервизора. Тот же критерий применим в мире контейнеров. Линию, которая удерживает недоверенный код, проводят на границе гипервизора, а не внутри общего ядра.
flowchart TB
accTitle: Как выбирать изоляцию от того, насколько доверяете коду
accDescr: Если нагрузке можно доверять, берите плотность и производительность изоляцией процессов; если код недоверенный или чужой, выбирайте границу гипервизора вроде контейнера с изоляцией Hyper-V, укреплённого Windows Sandbox с отключённой сетью или изолированной ВМ
trust{"Коду можно доверять?"} -->|Да| dens["Изоляция процессов (плотность)"]
trust -->|Нет / чужой код| bound["Выбрать границу гипервизора"]
bound --> opt1["Контейнеры с изоляцией Hyper-V"]
bound --> opt2["Укреплённый Sandbox или изолированная ВМ"]
Рис. 12: Режим изоляции — история безопасности прежде истории производительности, и доверие решает, где проводите линию.
Кстати, запуск контейнера с изоляцией Hyper-V внутри ВМ Hyper-V делает гипервизор двухслойным — вложенная виртуализация. Один уровень вложенности поддерживается в продакшене на средах, которые удовлетворяют условиям (процессор Intel с хостом Windows 10 / Windows Server 2016 или новее либо процессор AMD с хостом Windows 11 / Windows Server 2022 или новее и соответствующая версия конфигурации ВМ в каждом случае), и ещё одна предпосылка — настройка, которая выставляет расширения виртуализации внешней ВМ (ExposeVirtualizationExtensions на Set-VMProcessor в Hyper-V). Запуск WSL2 внутри ВМ поддерживается так же.9 Можно ли использовать WSL2 или Docker в ВМ разработки в облаке, тоже решает то, выставляет ли этот размер и конфигурация ВМ вложенную виртуализацию.
flowchart TB
accTitle: Структура вложенной виртуализации
accDescr: Облачная ВМ сидит на гипервизоре физического хоста, а внутри неё работает ещё один гипервизор (поддерживаемая вложенность — один уровень), чтобы поддержать WSL2 и контейнеры с изоляцией Hyper-V
phys3["Гипервизор физического хоста"] --> cvm["Облачная ВМ (машина разработки)"]
cvm --> nhv["Гипервизор внутри ВМ (уровень вложенности 1)"]
nhv --> w2["WSL2"]
nhv --> hvc["Контейнер с изоляцией Hyper-V"]
nhv -.-> limit["Поддерживаемая вложенность — один уровень"]
Рис. 13: Причина, почему wsl работает внутри облачной ВМ, в том, что вложенная виртуализация официально поддерживается только на один уровень.
5.3. Спектр изоляции и лёгкости
Если выстроить состав до сих пор на одной оси, выглядит так.
flowchart TB
accTitle: Спектр силы изоляции и лёгкости
accDescr: Контейнеры с изоляцией процессов самые лёгкие, но разделяют ядро; WSL2, Sandbox и контейнеры с изоляцией Hyper-V — лёгкие ВМ с выделенным ядром (Sandbox облегчает разделением, WSL2 — ядром под задачу); полная ВМ самая тяжёлая, но универсальная
ax["Легко ← → Тяжело"] ~~~ p1
p1["Process isolation (общее ядро)"] --> p2["WSL2 / Sandbox / Hyper-V (лёгкие ВМ)"]
p2 --> p3["Полная ВМ (полная копия)"]
p1 -.-> n1["Граница: пространства имён"]
p2 -.-> n2["Граница: гипервизор"]
p3 -.-> n3["Граница: гипервизор + независимость"]
Рис. 14: Группа лёгких ВМ — среднее решение, которое сохранило границу гипервизора и срезало дублирование; способ срезания делится на разделение у Sandbox и ядро под задачу у WSL2.
6. Посмотрите сами
Лёгкость и разделение — вещи, которые можно наблюдать на машине перед вами.
Время старта и подъём и спад памяти (WSL2). С открытым Диспетчером задач попробуйте следующее.
# Felt startup time (the first run starts the VM; the second and later are faster still)
Measure-Command { wsl -e true }
# Memory usage of the WSL2 VM (vmmem / Virtual Machine Memory)
Get-Process -Name vmmem* | Select-Object Name, WorkingSet64
# End the whole VM and watch the memory come back
wsl --shutdown
Если внутри WSL2 сделать большую сборку или файловую операцию, vmmem растёт, и можно наблюдать, как его возвращают разом через wsl --shutdown.
Разница скорости от того, куда кладёте файлы (WSL2). Положите один репозиторий на сторону Linux (~/repo) и на сторону Windows (/mnt/c/repo) и сравните время git status или распаковки — разница из раздела 3.2 проявится в числах.
Фон для direct map (Sandbox). Запустите Sandbox и посмотрите прирост памяти в Диспетчере задач на хосте. То, что прирост остаётся гораздо меньше, чем заставило бы представить «ещё один Windows», — эффект разделения рассказывает свою историю. Чтобы копнуть дальше в разбор памяти на стороне хоста, полезна статья про инструменты Sysinternals, которая покрывает, как использовать RAMMap и VMMap («Process Explorer / Handle / VMMap на практике»). Это, однако, инструменты, чтобы смотреть классификацию процессов и физической памяти на стороне хоста; само разделение с гостем они напрямую не наблюдают.
Режимы изоляции контейнеров (Docker / контейнеры Windows). Если есть среда контейнеров Windows, запустите один образ через docker run --isolation=process и --isolation=hyperv и сравните время старта и то, как это выглядит в Диспетчере задач (при изоляции процессов процессы внутри контейнера появляются в списке процессов хоста), — и почувствуете, где сидит линия изоляции.7 Изоляция процессов, однако, предполагает, что версии хоста и образа совпадают, и на клиентской ОС ограничена использованием для разработки и теста. Изоляция Hyper-V допускает более широкий набор сочетаний, поэтому сравнение делайте на совместимой паре.10
7. Три прочтения, которых стоит избегать на практике
7.1. «WSL2 медленный»
Медленный не WSL2, а путь файлового ввода-вывода, который пересекает границу ОС. Есть много случаев, где просто перенести проект на сторону Linux делает ощущение другой вещью.4 Наоборот, класть файлы, которые будут трогать инструменты Windows, на сторону Linux одинаково невыгодно по той же причине. Судите по «кладите на ту же ОС, что сторона, которая использует».
7.2. «То, что vmmem сильно вырос, — утечка памяти»
Память WSL2 растёт и сжимается со спросом, и освобождённые части возвращаются. На актуальном WSL файловый кэш тоже автоматически изымает autoMemoryReclaim (по умолчанию dropCache), поэтому «осталось большим» часто разрешается со временем.5 Если всё ещё остаётся, подтвердите, что autoMemoryReclaim не поставлен в disabled и что pageReporting, который отвечает за возврат освобождённых частей, не выключен (или что вы не на старом WSL), затем либо сделайте верхнюю границу явной через memory в .wslconfig, либо верните всё через wsl --shutdown на границе сеанса. Образ мысли о том, как отличить утечку от не-утечки, тот же, что во вступительной части серии про память, «Что на самом деле значит “использование памяти” Windows?».
7.3. «Это в контейнере, значит безопасно»
Контейнер с изоляцией процессов разделяет ядро, и по критерию Microsoft это не граница безопасности.8 Для запуска недоверенного кода или образца выбирайте изоляцию, у которой есть граница гипервизора, — контейнер с изоляцией Hyper-V, Windows Sandbox или выделенную ВМ. Граница гипервизора, однако, не всеобщее освобождение. Настройки Windows Sandbox по умолчанию имеют включённое сетевое подключение и могут выставить недоверенное приложение во внутреннюю сеть.1 Если используете его, чтобы запустить образец, укрепите изоляцию, отключив сеть и перенаправление буфера обмена в файле конфигурации .wsb, либо используйте выделенную ВМ в изолированной сети.
8. Итоги — закрывая серию
Пункты части 3.
- Лёгкость лёгкой ВМ — результат «перестать дублировать», а не «ослабить изоляцию».
- WSL2 запускает подлинное ядро Linux в управляемой лёгкой служебной ВМ, а дистрибутивы изолированы как контейнеры внутри этой ВМ.3 Правило производительности — класть файлы на ОС, которая их использует, а память растёт и сжимается динамически, с верхней границей, управляемой в
.wslconfig.45 - Windows Sandbox разделяет неизменяемые файлы ОС хоста через динамический базовый образ и также разделяет физические страницы целевых двоичных файлов ОС через direct map, поэтому не держит копию полного Windows.2 Всё равно нужно около 500 МБ на изменяемые файлы плюс память приложений, которые запускаете внутри.
- Режим изоляции контейнера выбирают при старте, и сторона, которую можно назвать границей безопасности, — изоляция Hyper-V.78
И если положить всю серию на одну страницу, выглядит так.
- Часть 1: Под Windows есть слой гипервизора, и сама хостовая ОС работает как корневой раздел. Арбитраж ЦП и памяти (SLAT) делает этот слой напрямую, а ввод-вывод синтетических устройств посредничает корневой раздел (VSP) по ту сторону VMBus.
- Часть 2: Этот слой используют не только чтобы изолировать ВМ друг от друга, но и чтобы провести границу сильнее ядра (VTL) внутри той же ОС. Безопасность Windows 11 по умолчанию построена поверх этого.
- Часть 3: На том же слое срезание дублирования делает возможной «виртуальную машину, которая стартует за секунды». Линия изоляции сохранена, и это стало повседневным инструментом.
flowchart TB
accTitle: Одна картина всей серии
accDescr: Гипервизор прямо на оборудовании — часть 1; разделение VTL0 и VTL1 внутри хостового Windows — часть 2; лёгкость WSL2, Sandbox и изоляции Hyper-V на том же слое — часть 3; контейнеры с изоляцией процессов разделяют ядро хоста; Sandbox облегчает разделением, WSL2 — ядром под задачу
hw3["Оборудование"] --> hv3["Гипервизор (часть 1)"]
hv3 --> rp3["Хостовый Windows (изоляция VTL — часть 2)"]
hv3 --> lw3["WSL2, Sandbox, изоляция Hyper-V (часть 3)"]
rp3 --> pc3["Контейнеры с изоляцией процессов (общее ядро)"]
lw3 -.-> mech3["Sandbox разделяет; WSL2 облегчает ядром под задачу"]
Рис. 15: Сложите три части — и получите общую картину грунта под актуальным Windows.
Виртуализация больше не технология серверной комнаты и не технология только для тех, кто поднимает ВМ. На грунте под вашим Windows она тихо поддерживает и безопасность, и опыт разработки — вот где мы сейчас.
Похожие статьи
- Глубины виртуализации Windows (часть 1) — где на самом деле работает ваш Windows? Гипервизор и разделы
- Глубины виртуализации Windows (часть 2) — память, которую не видит даже ядро: как работают VBS, HVCI и Credential Guard
- Глубины памяти Windows (часть 3) — объекты разделов и копирование при записи: чем на самом деле являются DLL и отображения файлов
- Как ускорить проверку приложений с помощью Windows Sandbox
- Ловушки перенаправления и виртуализации реестра 32/64 бит — Wow6432Node и проблема «значения, которое я записал, нет»
Смежные области консультирования
KomuraSoft LLC занимается настройкой сред разработки, которые используют WSL2 и контейнеры, проектированием сред проверки Windows-приложений и расследованием производительности и совместимости в виртуализированных средах.
- Разработка Windows-приложений
- Исследование дефектов и анализ первопричин
- Поддержка использования существующих активов и миграции
- Связаться с нами
Справочные ссылки
-
Microsoft Learn, Windows Sandbox. О том, что Windows Sandbox стартует за несколько секунд как одноразовая ВМ и отбрасывает всё при закрытии; о том, что запускает отдельное ядро гипервизором Microsoft, чтобы изолировать от хоста; и о том, что сетевое подключение включено по умолчанию и его можно отключить в файле конфигурации. ↩ ↩2 ↩3
-
Microsoft Learn, Windows Sandbox architecture. О том, что динамический базовый образ собирает полный образ Windows из доли неизменяемых файлов ОС хоста плюс чистой копии изменяемых файлов (около 500 МБ после установки); о том, что контейнер выделяет динамически в сотрудничестве с хостом, против статического выделения памяти традиционной ВМ, так что хост может изъять память; и о том, что direct map заставляет двоичные файлы ОС вроде ntdll.dll использовать те же физические страницы, что хост. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, What is the Windows Subsystem for Linux?. О том, что WSL2 запускает ядро Linux внутри лёгкой служебной ВМ; о том, что каждый дистрибутив работает как изолированный контейнер, разделяя сетевое пространство имён и ядро, при этом разводя пространства имён вроде PID, mount и user. ↩ ↩2 ↩3
-
Microsoft Learn, Comparing WSL Versions. О том, что ядро WSL2 собирает Microsoft из ветки Stable; о том, что WSL из Store получает обновления как пакет, отделённый от образа ОС, и применяет их через
wsl --update(на старом встроенном распространении — через Windows Update); о примерах производительности вроде до 20× для распаковки tar-архива; о том, что WSL1 быстрее для межОС-файловой системы, поэтому файлы стоит класть на ОС, которая их использует; и о том, что память растёт и сжимается с возвратом освобождённых частей, тогда как кэш может не вернуться, пока ВМ не завершится. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 -
Microsoft Learn, Advanced settings configuration in WSL. О том, что в разделе [wsl2] файла .wslconfig можно задать общий потолок памяти ВМ WSL2, число процессоров, подкачку и pageReporting (включён по умолчанию; отвечает за обнаружение и возврат неиспользуемой памяти); и о том, что экспериментальная настройка autoMemoryReclaim по умолчанию равна dropCache, так что память кэша изымается автоматически. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Use and configure Windows Sandbox. О том, что MappedFolders в файле конфигурации .wsb может предоставить папку хоста только для чтения или записываемой. ↩
-
Microsoft Learn, Isolation Modes. О том, что изоляция процессов контейнеров Windows разделяет ядро с хостом и изолируется через пространства имён; о том, что изоляция Hyper-V имеет по сути выделенное ядро внутри оптимизированной ВМ; и о том, что один образ можно запустить в любом режиме флагом при старте. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, Secure Windows containers. О том, что границей безопасности считают только контейнеры, изолированные гипервизором; о том, что контейнеры с изоляцией процессов не считают устойчивой границей безопасности; и о том, что изоляцию гипервизором стоит выбирать во враждебном мультиарендном сценарии. ↩ ↩2 ↩3
-
Microsoft Learn, What is Nested Virtualization?. О том, что запуск контейнеров с изоляцией Hyper-V внутри ВМ Hyper-V (один уровень вложенности) поддерживается в продакшене; о требованиях — процессор Intel с Windows Server 2016 / Windows 10 или новее либо процессор AMD с Windows Server 2022 / Windows 11 или новее плюс соответствующая версия конфигурации ВМ в каждом случае; о том, что выставление расширений виртуализации внешней ВМ (ExposeVirtualizationExtensions) — предпосылка; и о том, что запуск WSL2 внутри ВМ Hyper-V поддерживается. ↩
-
Microsoft Learn, Windows container version compatibility. О том, что изоляция процессов предполагает совпадение версий хоста и образа контейнера; о том, что изоляция Hyper-V может запустить образ версии ОС, отличной от хоста; и о том, что изоляция процессов на клиентской ОС ограничена использованием для разработки и теста. ↩
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Глубины виртуализации Windows (часть 1) — где на самом деле работает ваш Windows? Гипервизор и разделы
Когда включают Hyper-V, сам хостовый Windows работает поверх гипервизора как корневой раздел. Статья разбирает основы виртуализации через...
Глубины виртуализации Windows (часть 2) — память, которую не видит даже ядро: как работают VBS, HVCI и Credential Guard
На чистой установке на совместимом оборудовании VBS включена по умолчанию и с помощью гипервизора и SLAT создаёт изоляцию сильнее ядра. С...
Как ускорить проверку приложений с помощью Windows Sandbox
Разбираем, как использовать Windows Sandbox для эффективной локализации проблем с правами администратора, воспроизведения сценариев в чис...
Win32 Thread Pool API — параллелизм без создания потоков через CreateThreadpoolWork
По всему нативному коду разбросаны вызовы CreateThread? Статья разбирает Thread Pool API Win32, переработанный в Vista, — четыре объекта ...
Именованные каналы на практике — стандартный IPC Windows: от проектирования до безопасности
Практическое руководство по именованным каналам — стандартному межпроцессному взаимодействию Windows. Статья по первичным источникам разб...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- WSL2 — это ВМ?
- Да. WSL2 запускает подлинное ядро Linux, собранное Microsoft, внутри лёгкой служебной ВМ. ВМ управляет WSL за кадром, поэтому проект никогда не заставляет пользователя думать о настройках ВМ или ожидании загрузки. Каждый дистрибутив Linux работает как изолированный контейнер внутри этой управляемой ВМ.
- Почему файловые операции под /mnt/c в WSL2 медленные?
- Потому что доступ из ядра Linux WSL2 к файловой системе стороны Windows идёт через общий доступ к файлам, который пересекает границу ОС. Операции на файловой системе Linux (виртуальный диск ext4) быстрые, поэтому правило — держать файлы проекта на той же стороне ОС, что и инструменты, которые с ними работают.
- Большое использование памяти процессом vmmem — это утечка?
- В большинстве случаев это не утечка. Память WSL2 растёт и сжимается с использованием, а память, которую процессы освободили, возвращается Windows при настройке pageReporting, которая включена по умолчанию. Страницы файлового кэша тоже автоматически изымает актуальный WSL через autoMemoryReclaim в .wslconfig (по умолчанию dropCache). В средах, где эти настройки отключены, или на старом WSL память может оставаться до выхода ВМ; в таком случае задайте верхнюю границу настройкой memory или верните её через wsl --shutdown.
- Как Windows Sandbox загружает полный Windows с нескольких сотен мегабайт диска?
- Через механизм под названием динамический базовый образ. Он разделяет неизменяемые файлы ОС из Windows, уже установленного на хосте, и держит чистую копию только небольшого числа изменяемых файлов. Это позволяет собрать полный загружаемый образ, не храня полную копию Windows.
- Контейнеры безопаснее ВМ?
- Зависит от режима изоляции. Контейнеры с изоляцией процессов разделяют ядро с хостом, и Microsoft не считает это устойчивой границей безопасности. Когда обрабатываете враждебный код, нужна изоляция Hyper-V, которая даёт каждому контейнеру собственное выделенное ядро.
Об авторе
Страница с профилем автора статьи.
Го Комура
Представитель KomuraSoft LLC
Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.