Windows и оперативная память

В этой статье я хочу поделиться с вами знаниями о том как используется оперативная память в операционной системе Windows. То есть как система работает с памятью, какие в ней есть технологии и алгоритмы. Из статьи вы узнаете чем виртуальная память отличается от физической, как происходит выделение памяти процессам, что такое рабочий набор, swap и многое другое. Познакомимся с такими утилитами как: RAMMap, Process Explorer, Testlimit, Strings, NotMyFault и poolmon. Статья вышла объемной, так что наливайте себе кофе или чай и читайте не спеша.

Виртуальная и физическая память в ОС Windows

Для каждого процесса, в операционной системе Windows, выделяется некоторый объём оперативной памяти. Процесс не обязательно должен использовать весь выделенный объем памяти, он может занять всего лишь часть. Этот объем памяти называется виртуальным адресным пространством или проще виртуальной памятью процесса.

Выделенная память для процесса

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

Физическая память

Виртуальную память так назвали, потому что процесс думает что он один единственный в операционной системе Windows. Процесс видит только своё виртуальное адресное пространство и не знает сколько в системе реально физической памяти.

Работу виртуальной и физической памяти можно представить, таким образом:

  • Процесс помещает свои данные в ячейки памяти, которые принадлежат его виртуальному адресному пространству.
  • Виртуальные ячейки связываются с физическими ячейками в оперативной памяти или swap.
  • И в итоге, процессу не обязательно знать про физическое расположение памяти.
Виртуальная и физическая память Windows

Ограничения на память

Размер виртуального адресного пространства теоретически ограничивается архитектурой компьютера.

  • 32-разрядная — 4 ГБ (232).
  • 64-разрядная — 16 ЭБ (264) = 16777216 TB

Но операционная система Windows накладывает дополнительные ограничения на память.

Версия / Редакция ОС32-разрядная64-разрядная
Windows 10 / 11 Home4 GB128 GB
Windows 10 / 11 Pro4 GB2 TB
Windows 10 / 11 Enterprise4 GB6 TB
Windows Server 2019 Standard и Datacentr24 TB
Windows Server 2022 Standard и Datacentr256 TB
Windows Server 2025 Standard и Datacentr256 TB

А реальные лимиты на использование памяти могут быть ещё меньшими из-за ограничений материнской платы и процессора.

Страницы памяти

Память, потребляемая процессами в системе Windows, состоит из оперативной памяти и swap. При этом процессы работают с виртуальной памятью и не задумываются, где физически находятся страницы памяти.

Преобразование виртуальной памяти в физическую происходит на уровне страниц. То есть виртуальная страница должна ссылаться на физическую страницу. Так как страница памяти это неделимая единица, то не может получиться так, чтобы часть страницы была в оперативной памяти, а другая часть в файле подкачки.

Размер виртуальных страниц бывает разным, они бывают малые = 4 КБ и большие = 2 МБ. А физические страницы всегда = 4 KB. Номера страниц записываются в особую таблицу (Page Table). Каждая запись в таблице страниц называется Page Table Entry (PTE). При этом малые страницы помещаются в одну таблицу, а большие в другую.

Страничная память

Преимущество больших страниц. Так как число больших страниц меньше, то и таблица состоит из меньшего числа строк, что увеличивает скорость обращения к данным.

А недостатки. Большая страница виртуальной памяти занимает 512 смежных малых страниц физической памяти. Из-за фрагментации памяти может возникнуть ситуация, когда в системе просто не останется столько смежных свободных страниц. И попытка выделения одной большой страницы завершится неудачей. Еще одним недостатком является то, что в одной большой странице памяти может быть записан и код и данные. Обычно код доступен только на чтение, а данные на чтение и запись. Но так как права назначаются на страницу целиком, то код тоже станет доступен на запись.

Особенность больших страниц. Файл подкачки не поддерживает такие страницы, из-за этого они всегда находятся в оперативной памяти.

Существуют также огромные страницы (huge page) = 1 ГБ. Большие страницы превращаются в огромные, если нужно выделить сразу большой блок памяти (больше 1 ГБ).

Диспетчер памяти

Диспетчер памяти — это часть исполняющей среды Windows, который находится в ядре системы. Диспетчер памяти занимается выделением виртуальной памяти процессам и связывает виртуальную память с физической.

Процесс может работать либо со своей памятью, либо (при наличии необходимых разрешений) с памятью другого процесса. Например, если процесс создает дочерний процесс, то ему по умолчанию даётся право работать с виртуальной памятью дочернего процесса. Это означает, что родитель может производить операции чтения и записи в памяти дочерних процессов.

Помимо этого у диспетчера памяти есть и другие задачи:

  • Отображение виртуальной памяти в физическую.
  • Запись виртуальных страниц в swap при нехватке памяти, а также возврат этих страниц при необходимости.
  • Выделение и освобождение виртуальной памяти.
  • Совместное использование памяти между процессами. То есть разруливание блокировок и прав доступа.
  • Отображение файлов в память, то есть Windows кэширует прочитанные файлы с диска.
  • Получение информации о диапазоне виртуальных страниц.
  • Изменение защиты виртуальных страниц.
  • Блокировка виртуальных страниц.
Работа диспетчера памяти Windows

Состояния страниц виртуальной памяти

Страницы виртуальной памяти могут быть в разных состояниях:

  • Свободные (free) — такими страницами не владеет ещё ни один процесс и их можно выделять новым процессам.
  • Зарезервированные (reserved) — диспетчер памяти их уже зарезервировал для каково-то процесса, но ещё не связал с физическими страницами.
  • Подтвержденные (committed) — они уже связанны с физической памятью, и их можно использовать для хранения информации.
  • Разделяемые (shareable) — это тоже подтвержденные страницы, но они могут использоваться разными процессами совместно.

При зарождении нового процесса диспетчер памяти системы Windows из свободных страниц выделяет ему память. То есть свободные страницы становятся зарезервированными для этого процесса. Этот процесс не связывает виртуальные страницы с физическими, что позволяет очень быстро резервировать память для новых процессов.

Во время работы процессу windows нужно помещать некоторые данные в зарезервированную память. И уже здесь, по мере надобности зарезервированные страницы подтверждаются. И так как подтверждается не весь диапазон сразу, то и системные ресурсы тратятся не значительно. Это позволяет сгладить пиковые нагрузки на систему.

Но бывает и так, что размер который потребуется процессу известен заранее. Тогда процесс может зарезервировать и подтвердить память одновременно.

В любом случае полученные подтвержденные страницы доступны для любого потока в процессе.

Состояния страниц виртуальной памяти

Некоторая часть страниц, в которые процесс успел записать данные, может быть выгружена на диск в swap. Это делается для того чтобы освободить оперативную память в системе windows. А при необходимости эти страницы возвращаются с диска обратно в оперативку, так как процессы напрямую не работают с данными в swap.

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

Testlimit — это утилита командной строки, которую можно использовать для стресс-тестирования вашего ПК путем моделирования условий нехватки ресурсов для памяти, дескрипторов, процессов, потоков и другого. Мы будем её использовать для выделения зарезервированной и подтверждённой памяти.

Во-первых запустим окно командной строки и выполним нашу утилиту с опциями -r 1 -c 800. Это действие выделит 800 MB зарезервированной виртуальной памяти. Обратите внимание, в 64 разрядной системе нужно запускать Testlimit64.exe.

>Testlimit64.exe -r 1 -c 800
Testlimit v5.24 - test Windows limits
Copyright (C) 2012-2015 Mark Russinovich
Sysinternals - www.sysinternals.com
Process ID: 1392

Из вывода утилиты мы можем заметить PID запущенного процесса, который равен 1392.

Найдём процесс в Диспетчере задач. Перейдем на вкладку Сведения и добавим столбец Выделенная память (Commit Size).

Image

Когда мы выделили 800 MB зарезервированной виртуальной памяти, то на самом деле мы использовали всего 1980 KB физической. Такой процесс резервирования памяти облегчает создание процессов. Процесс windows получит эту память, только если она ему потребуется.

Теперь выделим подтвержденную память, для этого используем опции -m 1 -c 800.

>Testlimit64.exe -m 1 -c 800
Testlimit v5.24 - test Windows limits
Copyright (C) 2012-2015 Mark Russinovich
Sysinternals - www.sysinternals.com
Process ID: 6920

Посмотрим на процесс в диспетчере задач:

Image

Как видим, при выделении 800MB подтверждённой памяти было выделено примерно 800MB.

Из этого эксперимента видна разница между резервированием и подтверждением памяти.

Диспетчер задач Windows и память

В Диспетчере задач можно посмотреть информацию по физической и виртуальной памяти на вкладке Производительность:

Image

Описание графиков:

  • Использование памяти. Общая высота графика — это объем оперативной памяти (без учета swap), который может использоваться. Синие заполнение — это уже используемая оперативная память в системе Windows.
  • Структура памяти. График показывает соотношение между различными состояниями страниц памяти. На графике слева на право показана:
    • используемая — память используется процессами, драйверами или оперативной системой Windows;
    • измененная — такую память можно освободить, но вначале содержимое из неё нужно записать на диск;
    • зарезервированная — эту память диспетчер памяти зарезервировал для процессов, но пока они её не используют. А ещё сюда входит кэш;
    • свободная — эта память будет отдаваться новым процессам Windows в первую очередь.

Описание значений:

  • Используется (сжатая) — физическая память, используемая в настоящее время. Объем сжатой памяти указан в скобках.
  • Доступно — объем памяти, доступной для использования операционной системой, процессами и драйверами. Равен суммарному размеру изменённой, зарезервированной и свободной памяти.
  • Выделено — это два числа, первое показывает используемую физическую память, а второе — общий объём физической памяти. Эти два числа равны значениям счетчиков производительности Committed Bytes и Commit Limit соответственно.
  • Кэшировано — сюда попадает дисковый кэш.
  • Выгружаемый пул и Не выгружаемый пул — размер выгружаемого и не выгружаемого пула ядра.

Выгружаемый и не выгружаемый пулы представляют собой ресурсы памяти, которые ядро и драйвера используют для хранения своих данных. Эта память режима ядра Windows, то есть обычные процессы, в эту память ничего не записывают. Выгружаемый пул можно поместить в swap, то есть выгрузить, а не выгружаемый нельзя.

Process Explorer и память

Для того чтобы посмотреть информацию о памяти В Process Explorer откройте меню View, выберите команду System Information и перейдите на вкладку Memory:

Image

Графики:

  • System Commit — объем общей занятой физической памяти, с учетом файла подкачки.
  • Physical Memory — объём занятой оперативной памяти, без учёта файла подкачки.

Ниже все значения разделены по блокам, что облегчает анализ, все значения даны в КБ.

Commit Charge показывает выделенную физическую память с учетом swap.

  • Current — текущее использование физической памяти.
  • Limit — общий объем доступной физической памяти.
  • Peak — пик использования памяти за время работы Process Explorer.
  • Peak/Limit — отношение пиковой нагрузки к объему физической памяти.
  • Current/Limit — отношение текущей нагрузки к объёму физической памяти.

Phisical Memory уже не учитывает swap.

  • Total — общий объем памяти.
  • Available — объем доступной памяти, то есть сумма свободной памяти и памяти которую можно быстро освободить.
  • Cache WS — дисковый кэш.
  • Kernel WS — память ядра Windows.
  • Driver WS — память драйверов.

Kernel Memory — информация по пулам ядра.

  • Paged WS — объем реально занятой памяти под выгружаемый пул.
  • Paged Virtual — объем выделенной виртуальной памяти под выгружаемый пул.
  • Paged Limit — лимит выгружаемого пула.
  • Nonpaged — объем невыгружаемого пула.
  • Nonpaged Limit — лимит невыгружаемого пула.

Paging — показывает процесс свопинга. Данные отображаются в виде дельты, за период обновления программы.

  • Page Fault Delta — число ошибок страниц. Когда процесс обращается к странице виртуальной памяти, а она оказывается не связанной с физической. В этом нет ничего плохого. Просто виртуальная страница свяжется с физической, а затем процесс повторится.
  • Page Read Delta — число страниц прочитанных из swap.
  • Paging File Write Delta — число страниц помещённых в swap.
  • Mapped File Write Delta — число страниц которые были записаны для сохранения замапленных файлов (об этом ниже).

Блок Paging List посвящён физическим страницам памяти и их состояниям будет разобран позже.

Mapped File

Пришло время познакомиться с понятием Mapped File, которое мы встречали в Process Explorer. В эту память помещаются библиотеки, исполняемые файлы и т.п. То есть параметр Mapped File Write Delta показывает число помещения в оперативную память таких файлов в единицу времени.

В Windows существует механизм совместного использования памяти между процессами. Этот механизм называется Shared Memory. Общую память можно определить как память, которая видна более чем одному процессу. Shared Memory относится только к виртуальной памяти. Например, если два процесса используют одну библиотеку, то она будет помещена в память только один раз.

Каждый процесс поддерживает собственные области памяти для хранения закрытых данных, но код общей библиотеки и неизменяемые страницы данных могут находиться в общем доступе без какого-либо вреда.

Посмотреть на файлы отображенные в памяти каким-то процессом можно с помощью Process Explorer. Настройте нижнюю панель для вывода представления DLL (Ctrl + l). Здесь вы можете увидеть все замапленные файлы (Mapped File), в числе которых могут быть:

  • DLL-библиотеки;
  • исполняемые файлы, например файлы с расширением .exe;
  • файлы данных, то есть дополнительные файлы необходимые процессу.
Image

То что такие файлы в системе Windows помещаются в память один раз, а используются многими процессами, очень хорошо экономит оперативную память в системе.

Средства защиты памяти

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

  1. Разделение на пользовательский режим работы и режим ядра. При этом потоки пользовательского режима не могут обращаться к памяти которая работает в режиме ядра.
  2. Закрытое адресное пространство. У каждого процесса имеется отдельное закрытое адресное пространство. Оно защищено от обращений к ней другими процессами. Даже shared memory на самом деле для каждого процесса выглядит как его собственная память. Просто виртуальные страницы памяти одного процесса и виртуальные страницы памяти другого процесса ссылаются на одни и те же физические страницы, где фактически находится общая библиотека. А диспетчер памяти разруливает блокировки и права доступа.
  3. Аппаратная защита. Современные процессоры предоставляют некоторую разновидность аппаратной защиты памяти. При этом одна часть памяти доступна на чтение и запись, а другая часть только на чтение. Например, страницы памяти, где располагается исполняемый код, помечаются как доступные только для чтения.
  4. Права доступа. Страницы общей памяти защищены правами доступа (ACL). И когда какой-либо процесс хочет получить доступ к страницам общей памяти, то вначале проверяются его права доступа к этим страницам.
  5. Предотвращение выполнения данных DEP. Data Execution Prevention — это набор программных и аппаратных технологий, позволяющих выполнять дополнительные проверки содержимого оперативной памяти и предотвращать запуск вредоносного кода. Функция DEP позволяет отразить целый класс атак. В частности, DEP позволяет блокировать вирусы и другие вредоносные программы, пытающихся выполнить свой код из областей системной памяти.

Посмотреть какие процессы поддерживают DEP можно в Process Explorer, добавив колонку:

Image
  • Enable (permanent). DEP включен потому что процесс относится к числу основных для Windows.
  • Enable. Процесс дал согласие на использование DEP.
  • n/a. DEP не используется.

Пулы системной памяти

Когда система только загружается, диспетчер памяти создает два пула памяти, с динамически изменяемым размером:

  • не выгружаемый пул — постоянно находится в оперативной памяти;
  • выгружаемый пул — может выгружаться и снова подгружаться в память.

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

Для анализа пулов можно использовать программу Poolmon (придется установить WDK Tools, можно без SDK). Запустить утилиту можно с помощью команды:

"c:\Program Files (x86)\Windows Kits\10\Tools\10.0.26100.0\x64\poolmon.exe"

Вот так выглядит окно Poolmon:

Image

Клавиша «?» во время выполнения Poolmon вызывает экран со справочной информацией. Чтобы выйти из справки нажмите Esc.

Клавишей «p» можно переключаться на режимы отображения:

  • оба пула,
  • только выгружаемый,
  • только не выгружаемый.

Например, клавишей «p» настройте чтобы выводился только Nonp, затем нажмете клавишу «d» для сортировки по столбцу Diff, так вы узнаете, какие структуры наиболее многочисленны в не выгружаемом пуле.

Image

У себя я вижу что-то с тегом FMsl. За описаниями тегов пулов, используемых Windows, обращайтесь к файлу Pooltag.txt в подкаталоге Triage каталога, в котором размещается инструментарий отладки для Windows (C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\triage). Также информацию по тегам можно получить утилитой string, показанной чуть ниже.

FMsl - fltmgr.sys   -       STREAM_LIST_CTRL structure

То-есть в моём случае это драйвер — fltmgr.sys. Это драйвер, который обеспечивает инфраструктуру для файловых системных фильтров (например, антивирусов, бэкап-решений).

Столбцы Poolmon:

  • Tag — тег указывает на драйвер который использует пул памяти;
  • Type — тип пула;
  • Allocs — количество всех операций выделения (в скобках изменение с момента последнее обновления программы);
  • Diff — разность между количеством выделений и освобождений памяти;
  • Bytes — общее количество байтов, потребляемых тегом (в скобках изменение с момента последнее обновления программы);
  • Per Alloc — размер одного экземпляра данного тега в байтах.

Диагностика утечки памяти в пуле

Проведем диагностику утечки памяти в пулах. Утечка генерируется программой Notmyfault из пакета Sysinternals.

Выполните следующие действия:

  1. Запустите программу Notmyfault.exe для разрядности вашей ОС.
  2. Notmyfault.exe загружает драйвер устройства Myfault.sys и выводит диалоговое окно с выбранной вкладкой Crash. Щелкните на вкладке Leak. Введите в поле Leak/second значение 1000 Кбайт.
  3. Щелкните на кнопке Leak Paged. Программа начинает отправлять драйверу Myfault запросы на выделение памяти из выгружаемого пула.
Notmyfault
  1. Пока в пуле существует утечка, откройте Диспетчер задач, перейдите на вкладку Производительность и выберите категорию Память. Обратите внимание: значение Выгружаемый пул постепенно растет.
  2. Чтобы определить, с каким тегом пулов связана утечка, запустите программу Poolmon и нажмите клавишу «В», чтобы отсортировать информацию по количеству байтов.
  3. Клавишей «Р» настройте, чтобы в Poolmon отображался только выгружаемый пул. Обратите внимание: тег пула Leak поднимается в начало списка. Также Poolmon помечает изменения в выделенной памяти подсветкой изменяемых строк:
Image
  1. Щелкните на кнопке Stop Paged, чтобы не исчерпать выгружаемый пул в вашей системе.
  2. Запустите программу Strings (из пакета Sysinternals), чтобы найти исполняемые файлы драйверов с тегом пула Leak. Это делается в командной строке:
>strings64.exe # запустите чтобы принять лиц. соглашения, и можете оборвать нажав Ctrl+C

Затем выполните команду ещё раз, чтобы найти нужный драйвер по тегу:

>strings64.exe %SystemRoot%\system32\drivers\*.sys | findstr Leak
C:\WINDOWS\system32\drivers\balloon.sys: BalloonLeak
C:\WINDOWS\system32\drivers\bthport.sys: Leaking zombie SDP connections
C:\WINDOWS\system32\drivers\myfault.sys: Leak
C:\WINDOWS\system32\drivers\myfault.sys: Leak
C:\WINDOWS\system32\drivers\ndis.sys: LeakedNblReaction

Здесь вы видите что к тегу Leak относится драйвер myfault.sys.

Таким образом, если вы видите, что какой-то из пулов начал расти. То теперь вы знаете как отследить какой из драйверов потребляет слишком много памяти.

Файл подкачки и другие страничные файлы

Если в системе Windows нагрузка на память становится слишком велика, то процессы могут выгружать свою память в файл, который расположен на жестком диске. Такой файл называется файлом подкачки. В Windows не один такой файл. Например приложения из магазина приложений выгружают свою память в отдельный файл. А еще есть отдельный файл для режима гибернации.

Файлы подкачки ещё называют страничными файлами, так как данные там хранятся в том же формате что и в оперативной памяти, то есть в страницах.

Ограничить размер файла подкачки в Windows можно следующем образом:

  1. Выполните команду sysdm.cpl.
Image
  1. У вас откроется окно Свойство системы. Перейдите на вкладку Дополнительно и в области Быстродействие щелкните на кнопке Параметры.
Image
  1. В открывшемся окне перейдите на вкладку Дополнительно. В области Виртуальная память нажмите на кнопку Изменить.
Image
  1. В открывшемся окне снимите флажок Автоматически выбирать объём файла подкачки. Ниже поставьте галочку Указать размер и укажите максимальный размер файла подкачки. После проделанного нажмите кнопку Задать.
Image

Кроме рассмотренного файла подкачки в системе Windows есть и другие страничные файлы. Все они находятся в корне системного диска:

  • c:\pagefile.sys — обычный файл подкачки.
  • c:\swapfile.sys — дополнительный файл подкачки, служащий исключительно для приложений UWP из магазина приложений. Эти приложения сбрасывают сюда память, когда вы их сворачиваете.
  • c:\hiberfil.sys — этот файл нужен для режима гибернации. Все страницы физической памяти помещаются в этот файл, перед переводом системы в режим гибернации.

Рабочий набор

Рабочий набор — это виртуальные страницы памяти в которых процесс хранит необходимые ему данные. Если объем свободной памяти компьютера превышает пороговое значение, страницы остаются в рабочем наборе даже если они не используются. А если свободная память окажется ниже порога, то страницы изымаются из рабочих наборов. Такие страницы могут быть помещены в кэш. То есть они все равно останутся в памяти. При обращении к таким страницам, процесс получит ошибку page fault и страница вернется из кэша.

Если возрастет нагрузка на оперативную память, то данные могут быть выгружены в swap. При этом возврат данных из подкачки займет большее времени чем возврат страниц из кэша.

Наблюдать за рабочим набором процесса можно с помощью Системного монитора.

  1. Находим оснастку Системный монитор:
Image
  1. Удаляем счетчик производительности, который был по умолчанию.
  2. И добавляем новый счетчик производительности:
    • Находим группу счетчиков Процесс, в ней находим процесс (я посмотрю за процессом browser).
    • Выбираем счетчики: Ошибок страниц/сРабочий набор и его пик.
    • Нажимаем кнопку Add и OK.
Image
  1. Переключаем внешний вид на Отчет.
  2. Смотрим данные:
    • Рабочий набор — это объем страниц в памяти для данного процесса в байтах. 
    • Рабочий набор (пик) — это максимальный объем страниц, который был в памяти для данного процесса за все время работы процесса. 
    • Ошибок страницы/с — это частота ошибок, когда поток не находит нужную страницу в памяти и её необходимо подгружать.
Image

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

Стеки потоков Windows

Поток внутри процесса может использовать память процесса, но в одном процессе могут работать несколько потоков. При этом каждый поток должен где-то хранить свои локальные переменные или функции. Для этого каждый поток в процессе имеет индивидуальный блок памяти для хранения своих стеков.

Диспетчер памяти выделяет каждому потоку 2 стека: стек ядра и пользовательский стек. По умолчанию на пользовательский стек вначале выделяется 1 МБ, но подтверждается только первая страница. Стек может расти по мере необходимости, при этом стек не может сжиматься. Программисты должны правильно рассчитать возможное количество потоков в одном процессе, чтобы не сильно нагружать виртуальную память. Например если приложение запустит 1000 потоков, то будет выделено 1 ГБ виртуальной памяти только для стеков пользовательского режима.

Но еще важнее стек ядра, который нагружает физическую память. Для него выделяется 12 КБ для x86 и 16 КБ для x64. Такие стеки находятся в адресном пространстве ядра. В отличии от пользовательских стеков, стеки ядра могут и расширяться и сжиматься.

Из этого следует, что стеки потоков нагружают память в системе и их количество ограничивается объемом памяти. Дальше мы на практике попытаемся создать максимальное количество потоков в системе и посмотрим на результаты.

Эксперимент с максимальным количеством потоков в системе

Чтобы попытаться создать максимальное количество потоков в системе можно воспользоваться утилитой testlimit. Опция -t создаёт потоки, а опция -n 64 — указывает что для каждого потока нужно резервировать 64 KB.

Но прежде запустите Диспетчер задач и перейдите на вкладку Производительность. Остановить утилиту вы сможете нажав Ctrl+C, и то если успеете, так как у вас очень быстро закончится память.

Если приготовились запускайте:

> Testlimit64.exe -t -n 64

Вот как это выглядит в диспетчере задач:

Image

На моей машине получилось дойти до 106900 потоков в одном процессе при 4 GB памяти. Это 106900 * 4KB = 417 MB в пользовательском режиме. И 106900 * 16KB = 1670 МБ в режиме ядра. И в общем получается = 2087 MB.

Чтобы увидеть увеличение стека ядра можно воспользоваться утилитой RamMap.

Вот например стек ядра до и после запуска Testlimit64.exe -t -n 64:

Устройство Windows. Стеки, изображение №1
До запуска  Testlimit64.exe -t -n 64
До запуска Testlimit64.exe -t -n 64
После запуска  Testlimit64.exe -t -n 64
После запуска Testlimit64.exe -t -n 64

А на вкладке Processes в утилите RAMMap мы видим наш процесс Testlimit64.exe:

RamMap. Вкладка "Processes"

Подкачка по требованию

Windows использует алгоритм подкачки, который называется Подкачка по требованию. Это означает что при старте процесса в память загружаются не все данные, а только те, которые нужны для начала его работы.

Когда процесс только начинает работать, не все необходимые ему данные успевают подгрузиться в его рабочий набор. Процесс при этом получает много ошибок страниц (page fault). Когда процесс получает ошибку страницы, диспетчер памяти загружает нужную страницу в его рабочий набор, а в месте с ней ещё несколько страниц. Подгрузка дополнительных страниц вместе с основой призвана уменьшить нагрузку на дисковую подсистему.

Но все равно такая стратегия замедляет запуск приложений и служб Windows. С таким замедлением призваны бороться две технологии диспетчера памяти: Предвыборка и Cупервыборка.

За супервыборку отвечает служба SysMain. Она анализирует две вещи. Во-первых, какие приложения используются чаще всего. И во-вторых, к каким данным эти приложения обращаются чаще всего. Эти данные заранее помещаются в оперативную память (cache) для более быстрого доступа к ним. Супервыборка может ускорить работу системы увеличив потребление оперативной памяти. Кроме этого, супервыборка способна продлить срок службы жестких дисков, так как на них уменьшается нагрузка.

Предвыборка (PreFetcher) — Это встроенный механизм оптимизации загрузки системы и приложений. Он анализирует все запускаемые приложения в течении 10 секунд (при запуске). При этом запоминается какие файлы и данные загружались в оперативную память. Предвыборка анализирует какие страницы загружались и из каких файлов. А при следующем запуске этого приложения все необходимые ему данные разом загрузятся в оперативную память. Это уменьшит нагрузку на жёсткий диск и ускорит запуск приложения.

Отключить или включить PreFetcher можно редактируя параметр реестра:

Компьютер\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters\EnablePrefetcher
0x00000000 — компонент отключен
0x00000001 — ускорение запуска приложений
0x00000002 — ускорение загрузки системы
0x00000003 — ускорение запуска приложений и загрузки системы

Файлы  PreFetcher хранятся в каталоге C:\Windows\Prefetch и имеют расширения pf:

Image

Имена таких файлов состоят из имени приложения и хеша приложения.

SuperFetch также создает в этом каталоге файл Layout.ini:

Image

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

Состояния физических страниц

В Windows существует база данных — PFN (Page Frame Nubber). Она содержит все страницы физической памяти и их состояния:

  • Active (valid) — на эту страницу есть корректная PTE запись. То есть виртуальная страница соединена с физической.
  • Transition — временное состояние страницы, означает что со страницей осуществляется операция ввода / вывода. При этом страницы пока еще нет ни в рабочем наборе ни в файле подкачки.
  • Standby — страница была в рабочем наборе, но уже удалена из него. При этом страница не изменялась с момента последний записи на диск.
  • Modified — как standby, но страница была изменена, и еще не успела записаться на диск.
  • Modified no-write — как modified, но помечена, чтобы не быть записанной на диск. Возможно страница ждет завершения транзакции.
  • Free — свободная страница. Но она содержит некие данные, оставленные предыдущим потоком.
  • Zeroed — обнуленные страницы. Это свободные страницы прошедшие процедуру обнуления. Эти страницы готовы для работы с новыми потоками.
  • Room — страницы доступные только для чтения.
  • Bad — страница в отношении которой была получена ошибка, например ошибка четности. Поэтому страница не может быть использована.

Утилита RamMap и состояния страниц

Посмотреть на состояния страниц можно с помощью утилиты RamMap:

Image

Столбцы в этой утилите показывают состояния страниц, а строки — чем эти страницы используются:

  • Process Private — страницы используются процессами;
  • Mapped File — страницы выделены для замапленных файлов;
  • Shareable — общие страницы памяти;
  • Page Table — страницы в которых хранятся таблицы страниц;
  • Paged Pool — выгружаемый пул;
  • Nonpages Pool — невыгружаемый пул;
  • System PTE — пул системных страниц. Таких как пространство ввода-вывода, стеки ядра и списки дескрипторов памяти, также тут могут находиться страницы виртуальных машин;
  • Session Private — память, которая является частной для определенного сеанса, вошедшего в систему. Она будет выше на серверах RDS;
  • Metafile — часть системного кеша который содержит метаданные NTFS;
  • AWE (Address Windowing Extensions) — позволяет приложению отображать различные представления физической памяти в свое адресное пространство, обычно это используется SQL или другими приложениями баз данных;
  • Driver Locked — страницы, заблокированные драйверами;
  • Kernel Stack — страницы, используемые стеками потоков ядра;
  • Unused — неиспользуемые страницы;
  • Large Page — большие страницы (> 2 MB).

Обратите внимание — все обнуленные страницы у нас не используются (Unused). Некоторые приватные страницы процессов находятся в переходном состоянии (transition). Страницы в состоянии modified no-write это метафайлы файловой системы (ожидают окончания транзакций).

Перемещения станиц памяти из состояния в состояние

Страницы меняют своё состояние таким образом:

  • когда диспетчеру памяти нужна обнуленная страница, он ищет их в списке обнуленных страниц;
  • если список обнуленных страниц пуст, то страница берется из списка свободных страниц и обнуляется;
  • а если и список свободных страниц пуст, то происходит поиск среди ожидающих страниц (standby и modified).

Когда страница выходит из рабочего набора она может быть в двух состояниях:

  • modified — еще не записались изменения на диск. Такие страницы проходят подсистему записи измененных страниц и становятся standby.
  • standby — уже записались изменения на диск. Такие страницы могут стать свободными (free), а после прохода через поток обнуления — обнуленными (zeroed).

Когда процесс завершается, то все его страницы из рабочего набора переходят сразу в список свободных страниц, затем такие страницы могут стать обнуленными.

Перемещение страниц

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

Поток обнуления страницы заполняет страницу нулями, чтобы следующий поток не получил доступ к данным предыдущего потока.

Давайте понаблюдаем за свободными и обнуленными страницами в Process Explorer. Для примера можете запустить Testlimit64.exe -d 1 -c 1500 и в системе появится процесс, который займет 1500 МБ памяти. А в момент завершения процесса (нажатия ctrl+c) в системе образуется много свободных страниц, которые затем перейдут в список обнуленных страниц.

Image

Страницы в состоянии Standby (которые могут стать свободными (free)) имеют приоритеты, это видно в утилите Process Explorer.

Image

Страницы с наименьшим приоритетом используются раньше, чем процессы с наивысшим приоритетом.

За приоритет отвечает система супервыборки. То есть самые активные данные получают наивысший приоритет и остаются в оперативной памяти дольше, а редко используемые данные сбрасываются на диск чаще и их страницы обнуляются.

Сжатие памяти

В MicroSoft разработали специальный алгоритм для сжатия страниц памяти — Microsoft Xpress. Этот алгоритм сжимает страницы приблизительно до 30-50%.

Чтобы этот механизм освобождал память а не нагружал её еще сильнее, придумали следующие требования.

  1. В системе не может быть не сжатой страницы и такой-же сжатой.
  2. Если страница не может быть сжата достаточно эффективно, то она и не будет сжиматься.
  3. Сжатые страницы должны отображаться как свободные, хотя на сомом деле это страницы рабочего набора одного из системных процессов (об этом ниже).

В десктопных версиях ОС сжатие памяти включено по умолчанию. Серверные версии начиная с Windows Server 2019 — поддерживают сжатие но по умолчанию оно выключено, его можно включить с помощью команды:

Enable-MMAgent -MemoryCompression

Допустим у нас есть:

  • 8 свободных страниц, которые могут быть использованы;
  • 2 страницы которые сейчас находятся в работе;
  • 6 страниц которые уже не являются частью рабочего набора процессов, но содержат не сохраненные данные.
Алгоритм работы сжатия страниц памяти - шаг 1

Дальше диспетчер памяти хочет провести усечение списка измененных страниц. Информация на страницах 11, 12, 13 сжимается и помещается в 1 страницу из свободных. А страницы 11, 12, 13 освобождаются.

Алгоритм работы сжатия страниц памяти - шаг 2

Дальше три страницы (14, 15, 16) сжались в две из свободных (2, 3):

Алгоритм работы сжатия страниц памяти - шаг 3

Дальше диспетчер памяти решил произвести усечение сжатых страниц. Для этого он страницы 1 и 2 перемещает в измененные.

Алгоритм работы сжатия страниц памяти - шаг 4

Всё это сжатие позволило освободить оперативную память не обращаясь к диску. Нагружался только процессор. Если произойдет нехватка памяти, то измененные страницы просто запишутся на диск, а так как это сжатые страницы то и записывать на диск придется меньше.

Сжатая память хранится в рабочем наборе процесса Memory Compression. Объем рабочего набора этого процесса должен совпадать в диспетчере задач со сжатой памятью:

Image

Этот процесс просто предоставляет адресное пространство, а сжимает данные не он а диспетчер памяти.


Если понравилась статья, подпишись на мой канал в VK или Telegram.

Другие статьи по Windows вы найдёте здесь.

Используемые утилиты:

Мы используем cookie-файлы для наилучшего представления нашего сайта. Продолжая использовать этот сайт, вы соглашаетесь с использованием cookie-файлов.
Принять
Отказаться
Политика конфиденциальности