Неожиданная обработка страниц (также VirtualLock = no op?)

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

Приложение (под WinXP Pro 32bit) резервирует больший раздел (1 ГБ) адресного пространства с помощью VirtualAlloc (MEM_RESERVE) , а позже выделяет умеренно большие блоки (20-50 МБ) памяти с помощью VirtualAlloc. (MEM_COMMIT) . Это делается в воркере заранее, чтобы как можно меньше задерживать основной поток. Очевидно, вы никогда не сможете гарантировать отсутствие ошибок страниц, если область памяти в настоящее время не заблокирована, но некоторые из них, безусловно, допустимы (и неизбежны). На удивление каждая страница дает сбой. Всегда.

Таким образом, предполагалось, что система создает страницы только лениво после их выделения, что тоже имеет смысл (хотя документация предлагает нечто иное). Достаточно честно, моя плохая.
Таким образом, очевидным обходным путем является VirtualLock / VirtualUnlock , который заставляет систему создавать эти страницы, поскольку они должны существовать после VirtualLock возвращается. Удивительно, но по-прежнему возникают ошибки на каждой странице .

Итак, я написал небольшую тестовую программу, которая выполняла все вышеперечисленные шаги последовательно, засыпая между ними по 5 секунд, чтобы исключить, что что-то не так в другом коде. Результаты были следующими:

  • MEM_RESERVE 1 ГБ ---> успех, нулевой процессор, нулевое время, ничего не происходит
  • MEM_COMMIT 1 ГБ ---> успех, нулевой процессор, нулевое время, рабочий набор увеличивается на 2 МБ, 512 ошибок страниц (соответственно 8 байтов метаданных, выделенных в пространстве пользователя на страницу)
  • для (... + = 128 КБ) {VirtualLock (128 КБ); VirtualUnlock (128кБ); } ---> Успешно, обнуление ЦП, нулевое время, ничего не происходит
  • для (... + = 4096) * addr = 0; ---> 262144 ошибок страницы, около 0,25 секунды ( ~ 95% времени ядра). Увеличение на 1 ГБ как для «рабочего набора», так и для «физического» внутри Process Explorer
  • VirtualFree ---> нулевой ЦП, нулевое время, и «рабочий набор», и «физический» мгновенно уходят * пуф *.

Я ожидал, что, поскольку каждая страница была заблокирована один раз, она должна физически существовать по крайней мере после этого . Конечно, он все еще может перемещаться в WS и обратно по мере превышения квоты (просто изменяя одну ссылку, пока имеется достаточная RAM). Тем не менее, ни время выполнения, ни рабочий набор, ни показатели физической памяти, похоже, не поддерживают этого. Скорее, как это выглядит, каждая отдельная страница, к которой осуществляется доступ, создается после сбоя, даже если она была заблокирована ранее.Конечно, я могу прикоснуться к каждой странице вручную в рабочем потоке, но должен быть и более чистый способ?

Я делаю неверное предположение о том, что VirtualLock должен делать или я что-то не понимаю в виртуальной памяти? Есть идеи, как сообщить ОС "чистым, законным, рабочим" способом, что мне нужна память, и я буду хотеть ее по-настоящему ?

ОБНОВЛЕНИЕ:
В ответ на предложение Гарри Джонстона я попробовал несколько проблематичный подход, фактически вызвав VirtualLock на гигабайте памяти. Чтобы это удалось, вы должны сначала установить размер рабочего набора процесса соответствующим образом, поскольку квоты по умолчанию равны 200k / 1M, что означает, что VirtualLock не может заблокировать регион больше 200k (или, скорее, он не может заблокировать более 200k всего , и это минус то, что уже заблокировано для ввода-вывода или по другой причине).

После установки минимального размера рабочего набора 1 ГБ и максимального 2 ГБ все ошибки страницы происходят в момент вызова VirtualAlloc (MEM_COMMIT) . «Виртуальный размер» в Process Explorer мгновенно увеличивается на 1 ГБ. Пока все выглядело действительно очень хорошо.
Однако, если присмотреться, «Физическая» остается такой, какая она есть, реальная память действительно используется только в тот момент, когда вы ее касаетесь.

VirtualLock остается невыполнимой (ошибочной), но повышение минимального размера рабочего набора типа приблизилось к цели.

Однако есть две проблемы с изменением размера WS.Во-первых, вам обычно не полагается иметь гигабайт минимального рабочего набора в процессе, потому что ОС изо всех сил пытается заблокировать этот объем памяти. В моем случае это было бы приемлемо (на самом деле это более или менее то, о чем я прошу).
Более серьезная проблема заключается в том, что для SetProcessWorkingSetSize требуется право доступа PROCESS_SET_QUOTA , что не проблема для "администратора",но он терпит неудачу, когда вы запускаете программу как ограниченный пользователь (по уважительной причине), и запускает «разрешить возможно вредоносную программу?» предупреждение о каком-то известном российском антивирусе (для нет веской причины, но, увы, отключить его нельзя).

5
задан Damon 25 October 2011 в 12:54
поделиться