Как работает память / фиксация в Windows 10?

Этот вопрос вызван следующими регулярно наблюдаемыми явлениями, для которых я хотел бы найти объяснение:

  1. Текущий коммит регулярно превышает Физическое использование + размер файла подкачки. Что с этим? Разве это не может быть невозможно? [Это, кажется, может быть из-за сжатия. Что превращает вопрос в: почему лимит коммитов не повышается или что-то еще? Т.е. какой смысл сжимать, если это не помогает с использованием памяти?]
  2. Иногда это достигает экстремальных уровней, когда текущая фиксация более чем вдвое превышает использование физической памяти
  3. Когда коммитный заряд заполняется, и окна начинают просить меня закрыть вещи, большую часть времени физическая память находится на уровне около 60%. Это кажется ужасно неэффективным.

Это в Windows 10, как сообщает Process Explorer.

Последний вопрос, на который я хотел бы ответить, заключается в следующем: могу ли я отказаться от искусственного раздувания файла подкачки до уровней, на которых мой истощенный для пространства твердотельный накопитель плохо приспособлен для того, чтобы я мог эффективно использовать свою физическую память? (Или даже если он не был настолько полным. То есть я бы хотел избежать таких предложений, как "Сделать X/Y/Z для вашего файла подкачки".)

1 ответ

Решение

Это на самом деле довольно просто, если вы понимаете, что плата за коммит представляет собой только потенциальное - но "гарантированно доступное, если вы этого хотите" - использование виртуальной памяти, тогда как "частный рабочий набор", который по сути является ОЗУ, используемым "выделенной" памятью, - фактическое использование, так же как пространство файла подкачки. (Но это не все использование ОЗУ, потому что есть другие вещи, которые используют ОЗУ).

Предположим, мы говорим о 32-битных системах, поэтому максимальное виртуальное адресное пространство, доступное каждому процессу, обычно составляет 2 ГиБ. (В 64-разрядных системах нет существенных различий в любом из следующего, за исключением того, что адреса и размеры могут быть больше - гораздо больше.)

Теперь предположим, что программа, запущенная в процессе, использует VirtualAlloc (Win32 API) для "фиксации" 2 МБ виртуальной памяти. Как и следовало ожидать, это будет отображаться как дополнительные 2 МБ фиксации, и в процессе будет доступно на 2 МБ меньше виртуального адресного пространства для будущих выделений.

Но он пока не будет использовать физическую память (RAM)!

Вызов VirtualAlloc вернет вызывающему абоненту начальный адрес выделенной области; область будет где-то в диапазоне от 0x10000 до 0x7FFEFFFF, то есть около 2 ГиБ. (Первый и последний 64 КБ или 0x10000 в шестнадцатеричном виде vas в каждом процессе никогда не назначаются.)

Но опять же - пока нет фактического физического использования 2 МБ хранилища! Не в оперативной памяти, даже в файле подкачки. (Существует крошечная структура, называемая "дескриптором виртуального адреса", которая описывает начальный va и длину частного зафиксированного региона.)

Так что у вас есть это! Зафиксированный заряд увеличился, а использование физической памяти - нет.

Это легко продемонстрировать с помощью инструмента sysinternals testlimit,

Некоторое время спустя, скажем, программа хранит что-то (то есть операцию записи в память) в этом регионе (не имеет значения, где). Под каким-либо регионом еще нет физической памяти, поэтому такой доступ приведет к ошибке страницы. В ответ на это диспетчер памяти ОС, в частности подпрограмма обработки ошибок страниц (для краткости "пейджер"… это называется MiAccessFault), будет:

  1. выделить ранее "доступную" физическую страницу
  2. настроить запись таблицы страниц для виртуальной страницы, к которой был осуществлен доступ, чтобы связать номер виртуальной страницы с вновь назначенным номером физической страницы
  3. добавить физическую страницу в приватный рабочий набор процесса
  4. и отклонить ошибку страницы, вызвав повторную попытку инструкции, которая вызвала ошибку.

Теперь вы "винили" одну страницу (4 КиБ) в процессе. И использование физической памяти будет соответственно увеличиваться, а "доступная" оперативная память будет уменьшаться. Фиксация заряда не меняется.

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

  1. ОС удаляет страницу из рабочего набора процесса.
  2. поскольку он был записан, поскольку он был внесен в рабочий набор, он помещается в измененный список страниц (в противном случае он попадет в список резервных страниц). Запись таблицы страниц по-прежнему отражает физический номер страницы страницы ОЗУ, но теперь ее бит "valid" очищен, поэтому при следующей ссылке на нее произойдет сбой страницы.
  3. когда измененный список страниц достигает небольшого порога, измененный поток средства записи страниц в процессе "Система" просыпается и сохраняет содержимое измененных страниц в файл подкачки (при условии, что он у вас есть), и...
  4. удаляет эти страницы из измененного списка и помещает их в резервный список. Теперь они считаются частью "доступной" оперативной памяти; но на данный момент они все еще имеют свое первоначальное содержание, когда они были в своих соответствующих процессах. Опять же, фиксация заряда не меняется, но использование оперативной памяти и частного рабочего набора процесса снижается.
  5. Страницы в списке ожидания теперь могут быть переназначены, то есть использованы для чего-то другого - например, для устранения ошибок страниц в любом процессе в системе или для использования SuperFetch. Тем не мение...
  6. Если процесс, потерявший страницу в измененном или резервном списке, попытается снова получить к ней доступ до того, как физическая страница будет переназначена (т. Е. Он все еще имеет свое первоначальное содержимое), ошибка страницы устраняется без чтения с диска. Страница просто возвращается в рабочий набор процесса, и запись в таблице страниц становится "действительной". Это пример "мягкой" или "дешевой" ошибки страницы. Мы говорим, что резервные и модифицированные списки образуют общесистемный кеш страниц, которые, скорее всего, скоро понадобятся снова.

Если у вас нет файла подкачки, шаги с 3 по 5 будут изменены на:

  1. Страницы находятся в измененном списке, так как их содержимое некуда записать.

  2. Страницы находятся в измененном списке, так как их содержимое некуда записать.

  3. Страницы находятся в измененном списке, так как их содержимое некуда записать.

Шаг 6 остается тем же, так как страницы в измененном списке могут быть возвращены в процесс, который потерял их как "мягкую" ошибку страницы. Но если этого не произойдет, страницы будут находиться в измененном списке до тех пор, пока процесс не освободит соответствующую виртуальную память (возможно, потому что процесс завершится).

Существует и другое использование виртуального адресного пространства и оперативной памяти, помимо частной выделенной памяти. Существует сопоставленное виртуальное адресное пространство, для которого резервным хранилищем является некоторый указанный файл, а не файл подкачки. Страницы отображаемых vas, которые перемещаются по страницам, отражаются в использовании ОЗУ, но отображенная память не вносит свой вклад в фиксацию, поскольку отображенный файл обеспечивает резервное хранилище: любая часть отображаемой области, которая не находится в ОЗУ, просто сохраняется в сопоставленный файл. Другое отличие состоит в том, что большинство отображений файлов могут быть разделены между процессами; a shared page that's already in memory for one process can be added to another process without going to disk for it again (another soft page fault).

And there is nonpageable vas, for which there is no backing store because it's always resident in RAM. This contributes both to the reported RAM usage and to the "commit charge" as well.

This it seems might be because of compression. Which transforms the question to: Why doesn't commit limit then go up or something? Ie what's the point of compression if it doesn't help with memory usage?

No. It has nothing to do with compression. Memory compression in Windows is done as an intermediate step, on pages that otherwise would be written to the pagefile. In effect it allows the modified page list to use less RAM to contain more stuff, at some cost in CPU time but with far greater speed than pagefile I/O (even to an SSD). Since commit limit is calculated from total RAM + pagefile size, not RAM usage + pagefile usage, this doesn't affect commit limit. Commit limit doesn't change with how much RAM is in use or what it's in use for.

When commit charge fills up and windows starts asking me to close things, most of the time physical memory is at around 60%. This seems horribly inefficient.

It isn't that Windows is being inefficient. It's the apps you're running. They're committing a lot more vas than they're actually using.

The reason for the entire "commit charge" and "commit limit" mechanism is this: When I call VirtualAlloc, I am supposed to check the return value to see if it's non-zero. If it's zero, it means that my alloc attempt failed, likely because it would have caused commit charge to exceed commit limit. I'm supposed to do something reasonable like try committing less, or exiting the program cleanly.

If VirtualAlloc returned nonzero, ie an address, that tells me that the system has made a guarantee - a commitment, if you will - that however many bytes I asked for, starting at that address, will be available if I choose to access them; that there is someplace to put it all - either RAM or the pagefile. ie there is no reason to expect any sort of failure in accessing anything within that region. That's good, because it would not be reasonable to expect me to check for "did it work?" on every access to the allocated region.

The "cash lending bank" analogy

It's a little like a bank offering credit, but strictly on a cash-on-hand basis. (This is not, of course, how real banks work.)

Suppose the bank starts with a million dollars cash on hand. People go to the bank and ask for lines of credit in varying amounts. Say the bank approves me for a $100,000 line of credit (I create a private committed region); that doesn't mean that any cash has actually left the vault. If I later actually take out a loan for, say, $20,000 (I access a subset of the region), that does remove cash from the bank.

But whether I take out any loans or not, the fact that I've been approved for a maximum of $100K means the bank can subsequently only approve another $900,000 worth of lines of credit, total, for all of its customers. The bank won't approve credit in excess of its cash reserves (ie it won't overcommit them), since that would mean the bank might have to turn a previously-approved borrower away when they later show up intending to take out their loan. That would be very bad because the bank already committed to allowing those loans, and the bank's reputation would plummet.

Yes, this is "inefficient" in terms of the bank's use of that cash. And the greater the disparity between the lines of credit the customers are approved for and the amounts they actually loan, the less efficient it is. But that inefficiency is not the bank's fault; it's the customers' "fault" for asking for such high lines of credit but only taking out small loans.

The bank's business model is that it simply cannot turn down a previously-approved borrower when they show up to get their loan - to do so would be "fatal" to the customer. That's why the bank keeps careful track of how much of the loan fund has been "committed".

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

Если вы хотите смоделировать сопоставленную и нестраиваемую память по этой аналогии... nonpageable - это небольшой заем, который вы должны взять и не допускать при открытии своей учетной записи. (Структуры без страниц, которые определяют каждый новый процесс.) Отображенная память похожа на то, как вы несете свои собственные деньги (файл, который сопоставляется) и храните их в банке, а затем вынимаете только отдельные части за раз (разбирая их по страницам). Почему бы не заняться этим сразу? Я не знаю, может быть, у вас нет места в вашем кошельке для всех этих денег.:) Это не влияет на способность других лиц занимать деньги, потому что внесенные вами деньги находятся на вашем собственном счете, а не в общем кредитном фонде. Эта аналогия начинает рушиться, особенно когда мы начинаем думать о разделяемой памяти, поэтому не стоит слишком углубляться.

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

Могу ли я отказаться от искусственного раздувания моего файла подкачки до уровней, на которых мой истощенный для пространства твердотельный накопитель плохо приспособлен для того, чтобы я мог эффективно использовать свою физическую память? (Или даже если он не был настолько полным. То есть я бы хотел избежать таких предложений, как "Сделать X/Y/Z для вашего файла подкачки".)

Что ж, извините, но если вы столкнулись с лимитом коммитов, вы можете сделать только три вещи:

  1. Увеличьте свою оперативную память.
  2. Увеличьте размер вашего файла подкачки.
  3. Запустите меньше вещей за один раз.

По варианту 2: Вы можете поместить второй файл подкачки на жесткий диск. Если приложения на самом деле не используют всю эту выделенную память - а это, по-видимому, не так, поскольку вы видите так много свободной оперативной памяти - вы на самом деле не будете часто обращаться к этому файлу страниц, поэтому его установка на жесткий диск не будет повредить производительность. Если медлительность жесткого диска все еще беспокоит вас, другой вариант - это получить маленький и, следовательно, дешевый второй SSD и поместить туда второй файл подкачки. Один из "showtopper" - это ноутбук без возможности добавить второй "несъемный" диск. (Windows не позволяет размещать файлы подкачки на съемных дисках, как все, что связано с USB.)

Вот еще один ответ, который я написал, который объясняет вещи с другой стороны.

ps: Вы спрашивали о Windows 10, но я должен сказать вам, что она работает одинаково в каждой версии семейства NT, начиная с NT 3.1 и предварительных версий. Вероятно, изменилось значение Windows по умолчанию для размера файла подкачки, от 1,5 или 1x объема ОЗУ до гораздо меньшего размера. Я считаю, что это было ошибкой.

Другие вопросы по тегам