Как читать «использование памяти» в Windows: Working Set, Private Bytes, Commit и файл подкачки

· Обновлено: · · Windows, Разработка Windows, Управление памятью, Working Set, Private Bytes, Commit, Файл подкачки, Мониторинг производительности, Расследование сбоев, Sysinternals

История изменений (1 обновлений, последнее 31 Aug 2026)

Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.

Русский текст переписан по текущему навыку технического перевода как полный перевод японского оригинала.
Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.22175976)

Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.

Го Комура (2026). Как читать «использование памяти» в Windows: Working Set, Private Bytes, Commit и файл подкачки. KomuraSoft LLC. https://comcomponent.com/ru/blog/windows-memory-usage-working-set-commit/

DOI (зарегистрированный архив)
10.5281/zenodo.22175976
DOI (последняя зарегистрированная версия)
10.5281/zenodo.22175977

В диспетчере задач у процесса в столбце «Память» стоит 1,2 ГБ. В Process Explorer Working Set — 1,5 ГБ, Private Bytes — 2,4 ГБ, а Size в VMMap ещё больше. По системе в целом читается «Выделено 19,6/31,8 ГБ» (Committed 19.6/31.8GB).

Так сколько гигабайт памяти это приложение в итоге использует?

Ответ: какое число смотреть, зависит от того, что вы хотите узнать. Нужен объём, который сейчас лежит в ОЗУ? Объём, выделенный именно этому процессу? Объём, который система обязалась и дальше обеспечивать? Или просто диапазон зарезервированных виртуальных адресов? Показатель будет разным.

Показатели памяти Windows путают тем, что на экране все они подписаны одним словом «память», хотя измеряют разные оси.

  • Сколько занято адресного пространства
  • Сколько израсходовано commit
  • Находится ли страница сейчас в физической ОЗУ
  • Страница частная для процесса или её можно разделять
  • Сколько ещё выделений система в целом способна обеспечить

Статья рассчитана на тех, кто в Windows 10/11 и актуальном Windows Server разбирает рост памяти приложения или нехватку памяти по системе. Она собирает в одну картину связь Working Set, Private Working Set, Private Bytes, Commit, Virtual Bytes, файла подкачки, Available и ошибок страниц.

Как отличить объекты .NET, которые сборщик ещё не успел убрать, от настоящей утечки, подробно разобрано в «.NET: как отличить ожидание GC от утечки памяти». Конкретная работа с VMMap и Process Explorer — в «Process Explorer / Handle / VMMap на практике». Эта статья держит в фокусе общую предпосылку обоих текстов: как читать числа со стороны ОС Windows.

1. Сначала выводы

  • Working Set — страницы, которые сейчас находятся в ОЗУ. В набор входят не только страницы, частные для процесса, но и те, которые можно разделять с другими процессами: код DLL, файлы, отображённые в память, и т. п.1
  • Private Working Set — та часть Working Set, которая сейчас принадлежит только этому процессу. Это удобное приближение «ОЗУ, которую этот процесс сейчас занимает один», но не весь объём, который выделило приложение.2
  • Private Bytes — частный commit этого процесса. Это отдельный показатель от того, лежит ли память сейчас в ОЗУ. Поле PagefileUsage в структуре Win32 API на актуальной Windows по сути тоже показывает тот же Commit Charge, а не число байт, реально записанных в файл подкачки.2
  • Строка «Выделено X/Y» (Committed) в диспетчере задач: X — текущий суммарный commit системы, Y — Commit Limit. X — не использование файла подкачки. Y примерно складывается из ОЗУ и файла подкачки.3
  • Reserve и Commit — разные вещи. Если диапазон виртуальных адресов только зарезервирован, его отложили на будущее: тот же объём ОЗУ и Commit Limit при этом не расходуется.45
  • Page Fault не обязан означать дисковый ввод-вывод. Есть программные ошибки страниц (soft), которые закрываются внутри ОЗУ, и аппаратные (hard), которые читают из файла подкачки, исполняемых файлов, файлов, отображённых в память, и т. п.16
  • Утечку памяти судят не по одному снятию, а по наклону при повторении одной и той же нагрузки. Особенно смотрите, продолжают ли Private Bytes и их разбивка расти ступеньками даже после окончания обработки и не возвращаются ли к тому же установившемуся состоянию.

Одной фразой: Working Set — «сколько сейчас в ОЗУ», Private Bytes — «сколько обещано именно этому процессу», Commit — «сколько обещала система в целом».

Как выбрать основной показатель памяти WindowsПоказатель зависит от того, что нужно узнать: объём страниц в ОЗУ, частный commit процесса, commit всей системы или диапазон виртуальных адресовсколько сейчас в ОЗУчастный обещанный объём процессаобещанный объём всей системызарезервированный диапазон адресовЧто вы хотите узнать об использовании памятиWorking SetPrivate BytesSystem CommitVirtual Bytes / ReservedНахождение в физической ОЗУЧастный Commit процессаСравнение с Commit LimitВиртуальное адресное пространство

Рис. 1: Сначала разложите наблюдение «памяти много» на четыре отдельных вопроса.

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 18, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. Четыре оси «использования памяти»

Сначала думайте о памяти Windows не как об «одном столбике», а по четырём осям.

Четыре независимые оси классификации одной страницыОтдельно проверяйте состояние виртуального адреса, чем обеспечены страницы в состоянии Committed, находятся ли они в физической ОЗУ и можно ли их разделять с другими процессамиОдну страницу смотрят по четырём осямСостояние адресаFree / Reserved / CommittedЧем обеспеченаPage-file-backed / File-backedНахождение в ОЗУResident / Not residentСовместное использованиеPrivate / Shareable

Рис. 2: Даже у одной страницы состояние адреса, обеспечение, нахождение в ОЗУ и совместное использование задаются отдельно.

Mapped — не состояние адреса рядом с Free, Reserved и Committed, а категория области. Страницы отображённого представления тоже могут быть Committed. Private — не носитель обеспечения, а классификация совместного использования. Поэтому обеспечение читайте как Page-file-backed или File-backed, а совместность — как Private или Shareable, по отдельности.

Если сложить эти четыре оси, основные показатели соотносятся так.

Состояние страницы Working Set Private Working Set Private Bytes Семейство Virtual Bytes
Частная для процесса, committed, в ОЗУ Входит Входит Входит Входит
Частная для процесса, committed, не в ОЗУ Не входит Не входит Входит Входит
Общая страница DLL или отображённого файла, в ОЗУ Входит Обычно не входит Обычно не входит Входит
Reserved, но ещё не committed Не входит Не входит Не входит Может входить
Неиспользуемый диапазон адресов Не входит Не входит Не входит Обычно не входит
Соответствие типов страниц основным показателям памятиПоказывает, какие показатели включают частные страницы в ОЗУ, частные вне ОЗУ, общие страницы в ОЗУ и только зарезервированные диапазоныPrivate, committed, в ОЗУPrivate, committed, не в ОЗУОбщая страница, в ОЗУReserved, не committedWorking SetPrivate Working SetPrivate BytesСемейство Virtual Bytes

Рис. 3: Working Set и Private Bytes считают разные множества страниц, поэтому между ними нет простого включения.

Важно вот что: Working Set и Private Bytes не находятся в простом отношении включения.

В Private Bytes входят страницы, частные для процесса, но сейчас не находящиеся в ОЗУ. В Working Set, наоборот, входят общие страницы — код DLL, разделяемая память, — которые Private Bytes не считает. Поэтому в зависимости от процесса и момента Working Set может быть больше Private Bytes или наоборот.

Кроме того, если просто сложить Working Set нескольких процессов, одну и ту же физическую страницу — например общую DLL — можно посчитать несколько раз. «Сумма Working Set всех процессов = используемая ОЗУ» не обязана быть верной.

3. Виртуальное адресное пространство: Reserve и Commit — разное

3.1. Виртуальный адрес — не адрес физической ОЗУ

У каждого процесса своё виртуальное адресное пространство. Указатель, с которым работает приложение, не указывает напрямую на место в физической ОЗУ: Windows через таблицы страниц сопоставляет виртуальные адреса физическим страницам или данным в файле.7

Поэтому даже на ПК с 64 ГБ установленной ОЗУ виртуальное адресное пространство конкретного 32-разрядного процесса обычно намного меньше. И наоборот, у 64-разрядного процесса виртуальное адресное пространство больше физической ОЗУ — это нормально.

3.2. Reserved значит только «адрес занят заранее»

MEM_RESERVE у VirtualAlloc резервирует непрерывный диапазон виртуальных адресов на будущее. На этом этапе с страницами не связано физическое хранилище, и диапазон нельзя ни читать, ни писать.45

Например, даже если база данных или среда выполнения резервирует диапазон адресов 8 ГБ «на вырост», одно это не расходует ни 8 ГБ ОЗУ, ни 8 ГБ Private Bytes.

3.3. Committed — обязательство обеспечить страницу, когда она понадобится

MEM_COMMIT переводит виртуальную страницу в состояние Committed и заставляет Windows обязаться предоставить нужное обеспечение. Разрешены ли чтение, запись или исполнение, решает отдельно защита страницы — PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_NOACCESS и так далее, — поэтому само по себе Committed не значит «можно читать и писать». В момент commit это учитывается в системном Commit Charge, но фактическая физическая страница может не назначаться до первого обращения. Страница, к которой обратились впервые, обнуляется, проходит Demand-zero fault и входит в Working Set.51

Поэтому одно и то же «выделили» на деле бывает тремя стадиями.

Три стадии от Reserve через Commit к нахождению в ОЗУПоказывает поток резервирования виртуального адреса, commit страницы и назначения физической страницы при первом обращении с входом в Working SetMEM_COMMITпервое обращение, Demand-zero faultесли не обращалисьMEM_RESERVE: зарезервировать диапазон адресовПопадает в семейство Virtual BytesCommitted: доступ по защите страницыПопадает в Private Bytes / System CommitНазначена физическая страница, в ОЗУПопадает в Working SetCommitted, но не в ОЗУ

Рис. 4: Reserve, Commit и первое обращение — отдельные события, и каждое двигает свой показатель.

Эти три стадии по отдельности двигают числа семейства Virtual Bytes, Private Bytes и Working Set.

3.4. Почему бывает OutOfMemory при свободной ОЗУ

Успех выделения памяти определяется не только свободной ОЗУ.

  • Процесс исчерпал своё виртуальное адресное пространство
  • Нет свободного диапазона адресов нужного размера, который был бы непрерывным
  • Общесистемный Commit Charge достиг Commit Limit
  • У Job Object, контейнера, среды выполнения или библиотеки свой предел
  • Это 32-разрядный процесс
  • Нативная куча фрагментирована

Даже на 64-разрядной Windows пользовательское виртуальное адресное пространство 32-разрядного процесса обычно 2 ГБ, если не задан IMAGE_FILE_LARGE_ADDRESS_AWARE. 32-разрядное приложение с этим флагом на 64-разрядной Windows может использовать до 4 ГБ.8

Поэтому «у ПК 20 ГБ свободной ОЗУ, а 32-разрядное приложение падает около 1,6 ГБ» — не противоречие. Это может быть вовсе не проблема ОЗУ, а фрагментация адресного пространства или жёсткий предел.

4. Working Set: страницы, которые сейчас в ОЗУ

Working Set — множество страниц в виртуальном адресном пространстве процесса, которые сейчас находятся в физической ОЗУ.1

В этом множестве смешано следующее.

  • Собственные куча и стек процесса
  • Код EXE и DLL и данные только для чтения
  • Файлы, отображённые в память
  • Разделяемая память
  • Страницы, ставшие частными для процесса после копирования при записи
  • Страницы, к которым обращались среда выполнения и разные библиотеки

4.1. Рост Working Set не обязательно значит, что выделили больше

Первое обращение к уже выделенной (Committed) странице может увеличить только Working Set, тогда как Private Bytes не меняется. То же бывает, когда большой файл отображают в память и читают последовательно: страницы с файловым обеспечением входят в Working Set, а Private Bytes почти не растёт.

Наоборот, когда Windows в ответ на давление памяти делает Trim Working Set, уменьшается только Working Set, хотя приложение логически всё ещё держит ту же память. Повторное обращение возвращает её через Page Fault.

Поэтому падение Working Set не обязательно значит «приложение освободило», а рост — «приложение заново выделило».

Типичный поток, в котором растёт и падает только Working SetТа же страница в состоянии Committed входит в ОЗУ при первом обращении, уходит из ОЗУ при Trim и возвращается при повторном обращении, а Private Bytes всё это время учитываетсяпервое обращениеTrim при давлении памятиPage Fault при повторном обращенииТа же страница в состоянии CommittedВ ОЗУНе в ОЗУВходит в Working SetНе входит в Working SetУчитывается в Private Bytes, пока committed

Рис. 5: Working Set растёт и падает вместе с нахождением в ОЗУ, но Private Bytes не уменьшается, пока commit той же страницы остаётся.

4.2. Working Set включает общие страницы

Если 10 процессов разделяют кодовые страницы одной DLL, эта страница может появиться в Working Set каждого процесса, хотя в физической ОЗУ существует только одна копия. Сумма Working Set, превышающая установленную ОЗУ, сама по себе ещё не признак беды.

Если нужно приблизиться к «ОЗУ, которую этот процесс сейчас занимает один», смотрите Private Working Set. Но и это не «вся память, которую процесс выделил» — строго частные страницы, которые сейчас находятся в ОЗУ.

4.3. Принудительно ужать Working Set — утечку не исправить

EmptyWorkingSet или SetProcessWorkingSetSize позволяют вытеснить страницы из Working Set процесса. Но это не операция, которая снимает commit или ссылки в куче. Видимое использование ОЗУ падает, Private Bytes не меняется, а следующее обращение может вызвать всплеск ошибок страниц.9

Если цифра в диспетчере задач уменьшается только сразу после кнопки «уменьшить память» и сразу возвращается, когда вы снова начинаете работать, это может быть просто Trim Working Set, а не настоящее «освобождение».

5. Private Bytes: частный commit процесса

Private Bytes — объём виртуальной памяти, выделенной (committed) исключительно для этого процесса. Это Commit Charge, который нельзя разделить с другим процессом, и неважно, находится ли память сейчас в ОЗУ. В PROCESS_MEMORY_COUNTERS_EX Microsoft этому значению соответствует PrivateUsage.102

В Win32 API есть ещё поле с запутывающим именем PagefileUsage, но актуальная документация определяет его как «Commit Charge этого процесса» и говорит, что это то же значение, что PrivateUsage. Иными словами, Private Bytes 2 ГБ не значит «в pagefile.sys записано 2 ГБ».2

На Private Bytes обычно влияют следующее.

  • Commit нативной кучи, которую используют HeapAlloc, malloc, new и подобные
  • Private Data, выделенные напрямую через VirtualAlloc
  • Выделенная область кучи GC .NET
  • Та часть стека потока, которая реально committed
  • Commit Charge на всё представление, которое резервируется при отображении представления копирования при записи (FILE_MAP_COPY)
  • Частные буферы, которые внутри держат библиотеки и SDK устройств

В представлении копирования при записи, созданном через FILE_MAP_COPY, каждая страница в итоге может стать частной, поэтому в момент отображения Windows резервирует Commit Charge, достаточный, чтобы обеспечить всё представление файлом подкачки. Из-за этого System Commit и Commit Charge процесса (Private Bytes) могут вырасти на размер всего представления ещё до того, как любая запись реально создаст частную копию.11

5.1. Почему Private Bytes не падает после free или GC

Даже когда память «освобождена» с точки зрения приложения, среда выполнения или аллокатор кучи может не сделать Decommit этой области обратно ОС, а оставить её для будущего повторного использования. Тогда Private Bytes остаётся высоким, хотя внутри приложения область уже пригодна к повторному использованию.

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

Поэтому высокий Private Bytes сам по себе не доказывает утечку. Смотреть нужно сравнение во времени:

  1. Повторите одну и ту же обработку одно и то же число раз
  2. Подождите одно и то же время после обработки
  3. Проверьте, возвращается ли Private Bytes на тот же уровень или выходит на плато
  4. Через VMMap или дамп кучи проверьте, какая область или тип выросли
Почему Private Bytes не падает после free или GCPrivate Bytes меняется по-разному в зависимости от того, возвращает ли аллокатор ОС область, которая приложению больше не нужна, или держит её для повторного использованияDecommit / Releaseдержит для повторного использованияПриложение помечает область ненужной через free / GCВозвращает ли аллокатор её ОСCommit Charge уменьшаетсяPrivate Bytes падаетОбласть остаётся committedPrivate Bytes остаётся высокимПулы, кэши, фрагментация

Рис. 6: То, что область стала пригодной к повторному использованию внутри приложения, не то же самое, что возврат её Commit ОС.

5.2. Сильный кандидат на утечку

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

Private Bytes
  ^
  |                    ________
  |             ______|
  |      ______|
  |_____|
  +----------------------------> Повторение одной и той же обработки

Впрочем, даже «лестница» может быть несколькими раундами роста от первой JIT-компиляции, шрифтов, декодеров изображений, пулов соединений или прогрева кэша, после чего стабилизируется. Важно не то, что растёт, а то, что не сходится к установившемуся состоянию.

6. System Commit: что на самом деле такое «Выделено X/Y»

Цифра «Выделено X/Y» (Committed) на вкладке «Производительность» → «Память» диспетчера задач — общесистемный показатель.

  • X: System Commit Charge — память в состоянии Committed, которую Windows сейчас обязалась обеспечить по всей системе
  • Y: System Commit Limit — предел commit, который система способна обеспечить

Commit Limit примерно складывается из физической ОЗУ и суммы всех файлов подкачки. Без файла подкачки получается чуть меньше установленной ОЗУ.36

Связь System Commit Charge и Commit LimitЧастный commit процессов, commit общих секций и commit ядра составляют текущее значение X, а физическая ОЗУ и файл подкачки поддерживают предел YX не может превысить YPrivate Commit каждого процессаSystem Commit Charge: XCommit общих секций с обеспечением файлом подкачкиCommit ядраФизическая ОЗУSystem Commit Limit: YФайл подкачки

Рис. 7: X — текущий обещанный объём, Y — предел, который может поддержать это обязательство; это не отображение использования файла подкачки.

В System Commit Charge входит не только сумма Private Bytes каждого процесса, но и Commit общих секций с обеспечением файлом подкачки, и Commit, который потребляет ядро. Поэтому одной суммы попроцессных Private Bytes недостаточно, чтобы полностью объяснить X.

6.1. Commit Charge — не использование файла подкачки

Возьмите систему с 16 ГБ ОЗУ, файлом подкачки 16 ГБ и Committed 20/31 ГБ.

Эти 20 ГБ не значат «в файл подкачки записано 20 ГБ». Это суммарный объём, для которого Windows обязалась предоставить обеспечение ОЗУ или файлом подкачки, когда понадобится, — для частных изменяемых страниц и тому подобного.

В этот момент могут одновременно держаться такие состояния:

  • Большая часть находится в ОЗУ
  • Часть вытеснена в файл подкачки
  • Часть committed, но к ней ещё не было первого обращения
  • Часть потреблена как commit на стороне ядра

Если хотите увидеть реальное использование файла подкачки, смотрите Paging File(*)\% Usage отдельно от Commit. Даже собственные материалы Microsoft объясняют, что высокое использование файла подкачки само по себе не обязательно указывает на проблему производительности и что судить нужно вместе с достижением Commit Limit, Modified Page List и фактическим вводом-выводом подкачки.6

6.2. Что происходит при приближении к Commit Limit

Когда System Commit Charge достигает Commit Limit, новые запросы commit обеспечить нельзя. Это ведёт к отказам выделения памяти процессов, падениям приложений и неотзывчивости системы.3

Здесь X/Y Commit важнее, чем «свободная ОЗУ». Даже если Trim Working Set освободит ОЗУ, достижение Commit Limit не снимается, пока сам Commit Charge не уменьшится.

6.3. Три роли файла подкачки

Файл подкачки в основном служит следующим ролям.

  1. Расширять Commit Limit
  2. Давать возможность вытеснить из ОЗУ редко используемые изменённые страницы
  3. В зависимости от конфигурации поддерживать системный дамп сбоя

Отключение файла подкачки — не простой случай «дисковый ввод-вывод всегда падает и всё становится быстрее». Скорее оно снижает Commit Limit, делает вероятнее, что изменённые, но сейчас ненужные страницы останутся в ОЗУ, и может сделать невозможным снять нужный дамп при сбое.36

Подходящий размер файла подкачки нельзя решить только по установленной ОЗУ. Microsoft сама объясняет, что обобщать нельзя, потому что пиковый System Commit Charge и нужный вид дампа сбоя различаются от системы к системе.6

7. Разбивка физической ОЗУ: не судите только по низкому Available

Физическая ОЗУ используется не только Working Set пользовательских процессов.

  • Working Set каждого процесса
  • Системный файловый кэш
  • Списки страниц вроде Standby, Modified, Free и Zeroed
  • Paged Pool / Nonpaged Pool ядра
  • Память, которую держат драйверы устройств
  • Хранилище сжатия памяти
  • Области, общие с GPU и другими устройствами или зарезервированные для них
  • Память, зарезервированная оборудованием

7.1. Available включает и кэш, который можно использовать повторно

Available MBytes Windows — не просто полностью неиспользуемая ОЗУ. Это показатель, который наряду с Free и Zeroed включает страницы Standby, которые при необходимости можно использовать повторно.12

  • Free: страницы, сейчас не выделенные ни под какую цель
  • Zeroed: страницы, обнулённые так, что их можно безопасно отдать другому процессу
  • Standby: страницы, покинувшие Working Set, но чьё содержимое ещё кэшировано в ОЗУ
  • Modified: страницы, чьё содержимое изменилось и которые перед повторным использованием нужно записать в подходящее обеспечение
Движение между Working Set и списками страницПоказывает уход неизменённых страниц в Standby и изменённых в Modified, затем повторное обращение, запись и повторное использованиеубирают неизменённую страницуубирают изменённую страницузапись завершенаповторное обращениеповторно под другую цельобнулениеобращение после выделенияWorking Set: используетсяStandby: кандидат на повтор с сохранением содержимогоModified: ждёт записиВыделена под другую цельFree: не используетсяZeroed: доступна для нового выделенияВходит в Available

Рис. 8: Available включает не только полностью свободную память, но и Standby, которую при необходимости можно использовать повторно.

«Выбросить весь кэш, чтобы увеличить свободную ОЗУ» не всегда выигрыш. Если нужные данные ещё сидят в Standby, повторное обращение может быстро вернуть их в Working Set без чтения с диска.

Поэтому даже если Free в диспетчере задач низкий, если Available достаточно и аппаратные ошибки страниц или ожидание диска не создают проблем, Windows может просто эффективно использовать ОЗУ как кэш.

7.2. Когда ОЗУ убывает без крупного процесса

Нередко потребление памяти остаётся необъяснённым даже после суммирования Private Working Set каждого процесса.

  • Файловый кэш и файлы, отображённые в память
  • Nonpaged Pool / Paged Pool
  • Страницы, заблокированные драйвером
  • Общие страницы
  • Сжатие памяти
  • Выделения, связанные с виртуализацией или GPU

В этом случае, вместо того чтобы продолжать смотреть на список процессов, проверьте Use Counts, Processes, Priority Summary и File Summary в RAMMap из Sysinternals. RAMMap — официальный инструмент, который раскладывает физическую память по назначению, списку страниц и файлу.13

Если растёт только Nonpaged Pool, это момент подозревать утечку на стороне драйвера или ядра, а не Private Bytes приложения в пользовательском режиме.

8. Page Fault: высокий счёт сам по себе не аномалия

Page Fault возникает, когда процесс обращается к странице, которой сейчас нет в его Working Set. Несмотря на слово «Fault» в имени, это не исключительный сбой — это обычный механизм, который двигает виртуальную память.1

8.1. Программная ошибка страницы (soft)

Закрывается без чтения с диска.

  • Страница ещё в Standby или Transition
  • Та же общая страница уже есть в Working Set другого процесса
  • К странице в состоянии Committed обратились впервые и назначили нулевую страницу
  • Упреждающее чтение диспетчера памяти уже внесло её в ОЗУ

Поэтому большой \Memory\Page Faults/sec не обязательно значит, что идёт дисковый ввод-вывод или задержка.

8.2. Аппаратная ошибка страницы (hard)

Требует чтения содержимого из хранилища обеспечения на диске. Источник не ограничен файлом подкачки.

  • Код и данные в .exe или .dll
  • Файл, отображённый в память
  • Файл подкачки
Ветвление программных и аппаратных ошибок страницПри обращении к странице вне Working Set это программная ошибка, если ввод-вывод хранилища не нужен, и аппаратная, если нуженНет: Standby, общая, Demand-zero и т.д.ДаОбращение к странице вне Working SetНужен ли ввод-вывод хранилищаПрограммная ошибка страницыВходит в Working Set без чтения дискаАппаратная ошибка страницыОткуда читаетсяEXE / DLLФайл, отображённый в памятьФайл подкачкиВходит в Working Set после загрузки

Рис. 9: Одно имя Page Fault не скажет, был ли дисковый ввод-вывод.

Microsoft среди счётчиков для измерения аппаратных ошибок перечисляет \Memory\Pages/sec, \Memory\Page Reads/sec и \Memory\Pages Input/sec. Поскольку их высота не обязательно значит нехватку памяти, соотносите их с Available MBytes, задержкой диска и фактическим временем отклика.6

8.3. Не ставьте один общий порог

Фиксированное значение вроде «всё выше 1000 Page Faults/sec аномально» меняет смысл в зависимости от хранилища, размера страницы, нагрузки и локальности доступа.

На практике выстройте следующее на одной шкале времени.

  • Memory\Available MBytes
  • Memory\Pages Input/sec
  • Memory\Page Reads/sec
  • Задержка чтения / Queue целевого диска
  • Working Set и Private Bytes целевого процесса
  • Время обработки приложения, таймауты и отзывчивость интерфейса

Если Available падает одновременно с ростом нагрузки, Pages Input/sec и ожидание диска растут, и время обработки тоже ухудшается, это даёт основания подозревать подкачку из-за давления физической памяти.

9. Какой экран или инструмент смотреть для чего

Что хотите узнать Показатель, который смотреть первым Основные инструменты
Объём, который целевой процесс сейчас держит в ОЗУ Working Set Диспетчер задач, Process Explorer, Get-Process
Частную часть этого — ОЗУ, частную процессу Private Working Set / Working Set - Private Столбцы «Подробности» диспетчера задач, Process Explorer, PerfMon
Объём commit, частный целевому процессу Private Bytes / Commit Size Process Explorer, PerfMon, VMMap, Get-Process
Диапазон виртуальных адресов процесса Virtual Bytes / Size Process Explorer, VMMap, Get-Process
Общесистемный запас commit Committed Bytes / Commit Limit Диспетчер задач «Производительность», PerfMon
Запас повторного использования физической ОЗУ Available MBytes Диспетчер задач, PerfMon
Разбивку Standby, Modified и файлового кэша Список страниц / разбивка по назначению RAMMap
Что выросло внутри Private Bytes Heap / Private Data / Managed Heap и т. д. VMMap, WinDbg, дампы конкретной среды выполнения
Подкачку с участием диска Pages Input/sec, Page Reads/sec, задержка диска PerfMon, WPR/WPA
Выбор инструмента расследования памяти WindowsИнструмент зависит от того, цель — один процесс или вся система, одна точка во времени или ряд, и нужно ли проследить удержание внутри среды выполнениядаразбивка одной точкивременной рядвся системаразбивка физической ОЗУшкала с ЦП, вводом-выводом и ожиданиямикуча .NETнативная кучаЧто нужно локализоватьЦель — один процесс?Одна точка или временной рядVMMapPerfMon / PowerShellРазбивка физической ОЗУ или шкала времениRAMMapWPR / WPAНужно ли проследить удержание внутри средыdotnet-dump / PerfViewWinDbg / Application Verifier

Рис. 10: Сначала решив область и шкалу времени, вы выбираете ровно тот инструмент, который нужен, не больше и не меньше.

9.1. Диспетчер задач

В диспетчере задач смотрите экраны раздельно.

  • «Процессы» или «Подробности»: семейства Working Set и Commit Size отдельных процессов
  • «Производительность» → «Память»: общесистемные In use, Available, Committed, Cached, Paged pool, Non-paged pool

Не судите только по столбцу с именем «Память» — щёлкните правой кнопкой заголовки столбцов на вкладке «Подробности» и добавьте нужные столбцы, например Working Set, Peak Working Set и Commit Size. Имена столбцов немного различаются в зависимости от версии Windows и языка отображения, поэтому подтвердите смысл столбца, прежде чем записывать значение.

9.2. Снятие временного ряда через PowerShell

Если известен идентификатор целевого процесса, тенденции Working Set, Private Bytes и Virtual Bytes можно снять вместе через Get-Process.

param(
    [Parameter(Mandatory)]
    [int]$ProcessId,

    [int]$IntervalSeconds = 5,
    [int]$SampleCount = 60
)

$samples = for ($i = 0; $i -lt $SampleCount; $i++) {
    $process = Get-Process -Id $ProcessId -ErrorAction Stop

    [pscustomobject]@{
        Timestamp      = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        ProcessId      = $process.Id
        WorkingSetMB   = [math]::Round($process.WorkingSet64 / 1MB, 1)
        PrivateBytesMB = [math]::Round($process.PrivateMemorySize64 / 1MB, 1)
        VirtualBytesMB = [math]::Round($process.VirtualMemorySize64 / 1MB, 1)
        Handles        = $process.HandleCount
        Threads        = $process.Threads.Count
    }

    Start-Sleep -Seconds $IntervalSeconds
}

$samples | Format-Table -AutoSize
$samples | Export-Csv .\memory-samples.csv -NoTypeInformation -Encoding utf8

Process.WorkingSet64 в .NET соответствует Working Set, PrivateMemorySize64 — Private Bytes, VirtualMemorySize64 — Virtual Bytes.141516

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

9.3. Система и процесс на одной шкале времени через PerfMon

Запись как минимум следующего вместе сильно упрощает локализацию.

\Process(<цель>)\ID Process
\Process(<цель>)\Working Set
\Process(<цель>)\Working Set - Private
\Process(<цель>)\Private Bytes
\Process(<цель>)\Virtual Bytes

\Memory\Available MBytes
\Memory\Committed Bytes
\Memory\Commit Limit
\Memory\Pages Input/sec
\Memory\Page Reads/sec
\Memory\Pool Nonpaged Bytes
\Memory\Pool Paged Bytes

Когда несколько процессов разделяют одно имя или во время мониторинга происходит перезапуск, одного имени экземпляра — Process(name) или Process(name#N) — недостаточно, чтобы зафиксировать цель. Записывайте ID Process для каждой выборки и принимайте только тот экземпляр, чьё значение совпадает с отслеживаемым PID. Когда охватываете перезапуск, меняющий PID, отдельно записывайте и время переключения.

Имена счётчиков производительности Windows могут локализоваться в зависимости от языка отображения. Если прямое указание английского имени в PowerShell не находит счётчик, добавьте его через графический интерфейс PerfMon или проверьте имена в локальной среде через Get-Counter -ListSet *.

9.4. Не путайте роли VMMap и RAMMap

  • VMMap: раскладывает виртуальную память и Working Set одного процесса на Heap, Image, Mapped File, Private Data, Managed Heap и подобное
  • RAMMap: раскладывает физическую ОЗУ всей системы по назначению, списку страниц, процессу и файлу

«Из-за чего выросли Private Bytes этого процесса» — работа VMMap; «на что ушла ОЗУ, которую не объясняет список процессов» — работа RAMMap.1713

10. Чтение симптомов по сочетаниям чисел

Наблюдаемый рисунок Первая гипотеза Что проверять дальше
Working Set растёт, Private Bytes стабилен Первое обращение к существующим страницам, общая DLL, отображённый файл, файловый кэш Image / Mapped File в VMMap, Pages Input/sec
Private Bytes растёт, Working Set стабилен Частный Commit вырос, но страница не в ОЗУ или её усекли (Trim) Heap / Private Data / Managed Heap в VMMap
Оба растут сразу после старта, затем выравниваются JIT, кэш, пул, прогрев инициализации Растёт ли снова при той же дополнительной нагрузке
Минимум Private Bytes поднимается с каждым раундом нагрузки Утечка, кэш без потолка или аллокатор, который держит память после освобождения Снимки VMMap до и после, дамп кучи
Только Working Set внезапно падает и возвращается с активностью ОС или приложение сделали Trim Working Set Private Bytes, Pages Input/sec, время отклика
X в Committed X/Y приближается к Y Общесистемное давление commit Крупнейшие потребители Private Bytes, Paged/Nonpaged Pool, настройки файла подкачки
Available низок, Pages Input/sec и задержка диска высоки Давление физической ОЗУ и аппаратная подкачка Крупнейшие потребители Working Set, RAMMap, корреляция нагрузки
Использование ОЗУ высоко, но крупного процесса нет Кэш, общие страницы, пулы ядра, драйверы, сжатие и т. д. RAMMap, Pool Nonpaged/Paged Bytes
Свободная ОЗУ есть, а падает только 32-разрядное приложение Предел виртуального адресного пространства или фрагментация Free/Reserved в VMMap, настройка LAA исполняемого файла
Private Bytes высок, но не растёт при повторной обработке Пул или кэш, который, возможно, держит пиковое значение Его предел, поведение повторного использования, стабильность после пика

Самое важное в этой таблице — читать её в сочетании, а не по одному значению.

11. Практическая процедура расследования утечки памяти

11.1. Сначала зафиксируйте условия воспроизведения и точку установившегося режима

Одного «растёт за несколько дней» недостаточно для сравнения.

  • Какую долю прогрева после старта включать
  • Из чего состоит один цикл работы
  • Сколько секунд ждать после одного цикла
  • Сколько раундов нужно, чтобы достичь потолка кэша
  • Можно ли использовать один и тот же ввод для исправной и проблемной сборок

Решите всё это.

11.2. Записывайте процесс и систему одновременно

Как минимум ведите следующий журнал с одними и теми же метками времени.

  • Working Set цели
  • Private Bytes цели
  • Virtual Bytes цели
  • Committed Bytes / Commit Limit системы
  • Available MBytes
  • Pages Input/sec
  • Число дескрипторов, число потоков
  • Число операций или обработанных элементов

Если Private Bytes процесса стабилен, а системный Commit продолжает расти, нужно расширить обзор на другие процессы, ядро, драйверы и общие секции.

11.3. Сначала решите, какое «измерение» растёт

  • Только Working Set: страницы в ОЗУ, общие или файловые, Trim и повторная загрузка
  • Private Bytes: частный commit процесса
  • Только Virtual Bytes: Reserve, отображение, фрагментация адресного пространства
  • Только System Commit: включая другие процессы и сторону ядра
  • Nonpaged Pool: сторона драйвера/ядра
  • Handles / GDI / USER: утечки ресурсов помимо памяти

Если пропустить этот порядок и сразу снимать дамп, придётся читать большой объём сведений не про ту область.

11.4. Переходите к разбивке

  • Нативный процесс: VMMap, WinDbg, Application Verifier, трассировка кучи
  • .NET: dotnet-counters, dotnet-gcdump, dotnet-dump, PerfView
  • Вся система: RAMMap, PerfMon, WPR/WPA
  • Пул ядра: PoolMon, WinDbg

VMMap показывает выделенную (committed) виртуальную память процесса и Working Set, назначенный каждой её части, в разбивке по типу. Насколько удаётся сузить рост Private Bytes до Heap, Private Data, Managed Heap или Mapped File, сильно меняет стоимость дальнейшего расследования.17

11.5. После исправления сравнивайте тенденцию в тех же условиях

Недостаточно, чтобы пиковое значение отличалось до и после исправления. Если отличается стартовое значение, сравнение легко переворачивается.

  • Одно и то же состояние старта
  • Один и тот же ввод
  • Одно и то же число операций
  • Одно и то же время ожидания
  • Один и тот же интервал выборки

— и сравнивайте минимум после каждого цикла и наклон. Доказательство исправления утечки — не «максимум стал меньше», а то, что рост теперь сходится, даже когда та же нагрузка повторяется.

12. Переформулировка распространённых заблуждений

Заблуждение 1: Память в диспетчере задач равна полному объёму, который выделило приложение

Переформулировка: Проверьте, какой это столбец. Для семейства Working Set это объём, который сейчас находится в ОЗУ; для семейства Commit Size — commit, частный этому процессу.

Заблуждение 2: Private Bytes равны байтам в файле подкачки

Переформулировка: Private Bytes — частный Commit Charge. Это логический обещанный объём, который включает и страницы, сейчас в ОЗУ, и страницы, которые при необходимости обеспечит файл подкачки.

Заблуждение 3: Commit X/Y равен использованию / ёмкости файла подкачки

Переформулировка: X — общесистемный Commit Charge, Y — Commit Limit. Файл подкачки расширяет Y, но X не переводится напрямую в использование на диске.

Заблуждение 4: Высокий Page Faults/sec значит свопинг на диск

Переформулировка: Сюда входят и программные ошибки. Проверьте Pages Input/sec, Page Reads/sec и задержку диска, чтобы увидеть, участвует ли реально дисковый ввод-вывод.

Заблуждение 5: Низкая свободная ОЗУ значит нехватку памяти

Переформулировка: Смотрите Available, Standby, аппаратную подкачку и время отклика. Заполнять ОЗУ кэшем, который можно использовать повторно, нормально.

Заблуждение 6: Сжать Working Set значит починить утечку памяти

Переформулировка: Возможно, вы только вытеснили страницы из ОЗУ. Проверьте, уменьшились ли реально Private Bytes и то, что удерживается внутри кучи.

Заблуждение 7: Рост Private Bytes подтверждает утечку

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

13. Итоги

  • «Использование памяти» Windows — не одно число. Думайте отдельно об адресном пространстве, commit, нахождении в ОЗУ и совместном использовании.
  • Working Set — страницы, которые сейчас в ОЗУ, включая и Private, и Shared. Private Working Set — частные страницы процесса внутри этого набора, которые сейчас в ОЗУ.
  • Private Bytes — частный Commit Charge процесса; это ни объём, сейчас находящийся в ОЗУ, ни объём, реально записанный в файл подкачки.
  • Committed X/Y — общесистемные Commit Charge / Commit Limit. Файл подкачки в основном поддерживает Commit Limit, вытеснение изменённых страниц и дампы сбоя.
  • Зарезервированный виртуальный адрес, страница в состоянии Committed и страница, к которой реально обратились и которая вошла в Working Set, — отдельные стадии.
  • Page Fault — нормальная работа, и программная ошибка не читает с диска. Аппаратные ошибки тоже могут идти не только из файла подкачки, но из EXE, DLL или отображённого файла.
  • Утечка памяти доказывается не размером в одной точке времени, а минимумом и наклоном после той же нагрузки вместе с разбивкой.
  • Базовый путь: VMMap для разбивки отдельного процесса, RAMMap для общесистемной физической ОЗУ, PerfMon для временного ряда и специализированный инструмент дампа для того, что происходит внутри среды выполнения.

В следующий раз, заметив в диспетчере задач, что «память растёт», начните с этого вопроса.

Растёт Working Set, Private Bytes, Virtual Bytes или System Commit?

Один этот вопрос делает точку входа в расследование заметно точнее.

Похожие статьи

Смежные области консультирования

KomuraSoft LLC занимается расследованием причин роста памяти Windows-приложений, деградации производительности после долгой работы, OutOfMemory в 32-разрядных процессах и нехватки памяти, которая проявляется только в среде заказчика. Мы сочетаем PerfMon, VMMap, RAMMap, WinDbg и диагностические средства .NET. Задача не сводится к выводу «памяти много»: локализуем, какая область растёт, при какой операции, почему и откуда на неё ссылаются или её удерживают.

Справочные ссылки

  1. Microsoft Learn, Working Set. О том, что Working Set процесса — множество страниц, которые сейчас находятся в физической памяти, включая общие страницы; о разнице между программными и аппаратными ошибками страниц; о страницах Transition; и об удалении страниц из Working Set. ↩ ↩2 ↩3 ↩4 ↩5

  2. Microsoft Learn, PROCESS_MEMORY_COUNTERS_EX2 structure. Об определениях WorkingSetSize, PrivateWorkingSetSize, PrivateUsage и SharedCommitUsage и о том, что и PagefileUsage, и PrivateUsage представляют Commit Charge процесса. ↩ ↩2 ↩3 ↩4

  3. Microsoft Learn, Introduction to page files. О том, что файл подкачки поддерживает вытеснение изменённых страниц, системные дампы сбоя и расширение System Commit Limit; об определениях System Commit Charge и Commit Limit; и об измерении через диспетчер задач и счётчики производительности. ↩ ↩2 ↩3 ↩4

  4. Microsoft Learn, Page State. О состояниях Free, Reserved и Committed виртуальной страницы и о том, что со страницами Reserved не связано физическое хранилище и они недоступны. ↩ ↩2

  5. Microsoft Learn, VirtualAlloc function. О разнице между MEM_RESERVE и MEM_COMMIT; о том, что commit учитывается против общей памяти системы и файла подкачки; и о том, что фактическая физическая страница иногда не выделяется до первого обращения. ↩ ↩2 ↩3

  6. Microsoft Learn, How to determine the appropriate page file size for 64-bit versions of Windows. О том, что размер файла подкачки зависит от пикового Commit Charge и требований к дампу сбоя; о том, что аппаратные ошибки страниц читают не только из файла подкачки, но и из EXE, DLL и файлов, отображённых в память; и о связанных счётчиках производительности. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  7. Microsoft Learn, Virtual Address Space. О том, что у каждого процесса своё независимое виртуальное адресное пространство и таблица страниц, и виртуальный адрес сам по себе не является физическим адресом. ↩

  8. Microsoft Learn, Memory Limits for Windows and Windows Server Releases. О том, что пользовательское виртуальное адресное пространство 32-разрядного процесса обычно 2 ГБ и на 64-разрядной Windows становится 2 ГБ или 4 ГБ в зависимости от IMAGE_FILE_LARGE_ADDRESS_AWARE. ↩

  9. Microsoft Learn, SetProcessWorkingSetSize function. О том, что минимум и максимум Working Set не гарантируют нахождение в ОЗУ; о возможности опустошить Working Set; и о том, что чрезмерные настройки или операции могут ухудшить производительность системы. ↩

  10. Microsoft Learn, Memory Performance Information. О соответствии между счётчиками производительности Windows, API управления памятью и отображением диспетчера задач, включая Working Set / Working Set - Private / Private Bytes объекта Process и Committed Bytes / Commit Limit объекта System. ↩

  11. Microsoft Learn, MapViewOfFile function. О том, что FILE_MAP_COPY делает каждую страницу потенциально копируемой при записи, поэтому Commit Charge на всё представление резервируется для обеспечения файлом подкачки в момент отображения. ↩

  12. Microsoft Learn, Understanding Node Metrics and Properties in HPC Cluster Manager. О том, что Available Physical Memory считается как сумма списков Zeroed, Free и Standby, и о значении каждого из этих списков страниц. ↩

  13. Microsoft Sysinternals, RAMMap. Об анализе использования физической памяти Windows по назначению, списку страниц, процессу, приоритету, физической странице и файлу. ↩ ↩2

  14. Microsoft Learn, Process.WorkingSet64 Property. О том, что WorkingSet64 возвращает Working Set процесса в байтах, соответствуя счётчику производительности Working Set объекта Process. ↩

  15. Microsoft Learn, Process.PrivateMemorySize64 Property. О том, что PrivateMemorySize64 возвращает память, частную процессу и не разделяемую с другими процессами, соответствуя счётчику производительности Private Bytes. ↩

  16. Microsoft Learn, Process.VirtualMemorySize64 Property. О том, что VirtualMemorySize64 возвращает объём виртуальной памяти процесса, соответствуя счётчику производительности Virtual Bytes. ↩

  17. Microsoft Sysinternals, VMMap. О разбивке выделенной (committed) виртуальной памяти процесса по типу и отображении физической памяти (Working Set), выделенной каждой части, вместе с подробной картой памяти. ↩ ↩2

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

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

Показывает ли столбец «Память» в диспетчере задач всю память, которую выделило приложение?
Нет. В диспетчере задач несколько столбцов памяти — семейство Working Set, семейство Private Working Set, Commit Size и другие, — и смысл зависит от экрана и столбца. Working Set — страницы, которые сейчас находятся в ОЗУ. Private Bytes или Commit Size — частный Commit Charge этого процесса. Не принимайте один столбец «Память» за весь объём, который выделило приложение, и не за величину утечки.
Чем Working Set отличается от Private Bytes?
Working Set — объём страниц, которые видны процессу и сейчас находятся в физической ОЗУ, включая общие страницы: код DLL, файлы, отображённые в память, и тому подобное. Private Bytes — объём памяти в состоянии Committed, которой пользуется только этот процесс; находится ли она сейчас в ОЗУ, неважно. Поэтому значения не совпадают, и между ними нет простого отношения «больше / меньше».
Означает ли «Выделено 18/32 ГБ» в диспетчере задач, что 18 ГБ записаны в файл подкачки?
Нет. Слева — текущий Commit Charge всей системы, справа — Commit Limit, который система способна обеспечить. Предел примерно складывается из ОЗУ и файла подкачки, но весь левый итог на файле подкачки не лежит. Большинство страниц в состоянии Committed находится в ОЗУ, а некоторым из них физическая страница ещё ни разу не назначалась. Страницы, которые можно снова прочитать из исходного файла — EXE, DLL, файлы, отображённые в память, — не обязаны увеличивать частный Commit на ту же величину, что и Working Set.
Бывает ли OutOfMemory, когда свободная ОЗУ ещё есть?
Да. Выделение может не пройти по причинам помимо физической ОЗУ: нехватка виртуального адресного пространства 32-разрядного процесса, отсутствие непрерывного свободного диапазона адресов, системный Commit Limit, пределы Job Object или среды выполнения. В частности, 32-разрядный процесс на 64-разрядной Windows обычно ограничен 2 ГБ пользовательского виртуального адресного пространства, если он не Large Address Aware.
Станет ли Windows быстрее, если отключить файл подкачки?
В общем случае этого нельзя утверждать. Без файла подкачки снижается системный Commit Limit, реже используемые изменённые страницы труднее вытеснить из ОЗУ, и меняется конфигурация дампов при сбое. Размер файла подкачки нужно выбирать по пиковому Commit Charge и нужному типу дампа — это не параметр, который отключают без оснований.
Если Page Faults/sec высокий, значит ли это, что памяти не хватает?
По одному этому счётчику не скажешь. Ошибки страниц бывают программными (soft): их закрывают страницы Standby в ОЗУ или страницы, общие с другим процессом, — и аппаратными (hard), которые читают с диска. Смотрите не только Page Faults/sec, а вместе, на одной шкале времени: Pages Input/sec, Page Reads/sec, Available MBytes, задержку диска и время обработки.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

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

Публичные ссылки

Вернуться в блог