Если вы пытались запустить этот пример из MSDN, иллюстрирующий создание проекции файла с большими страницами, то, скорее всего, вы столкнулись с ошибкой
ERROR_NOT_ALL_ASSIGNED
("Вызывающая сторона не обладает всеми необходимыми правами доступа.") при вызове AdjustTokenPrivileges
. В чём проблема?Функция
AdjustTokenPrivileges
включает привилегии, которые у вас уже есть (есть, но отключены). Думайте о ней, как о супер-герое, который не может использовать свои способности, пока он маскируется под обычного человека. Чтобы включить привилегию SeLockMemoryPrivilege
, вам уже нужно её иметь. Но где её взять?Вы можете получить привилегию, используя редактор групповых политик (group policy editor). Список привилегий сообщает нам, что
SeLockMemoryPrivilege
соответствует "Блокировка страниц в памяти" ("Lock pages in memory").Но почему выделение памяти большими страницами требует такую привилегию?
Потому что большие страницы не выгружаются на диск (not pageable). Это не является принципиальным недостатком: процессор и рад бы сбросить страницы на диск, но проблема в том, что надо делать это целиком. Т.е. или сбрасываем всю страницу или не сбрасываем ничего. На практике вы бы не хотели, чтобы малюсенькая операция ввода-вывода привела бы к копированию 2-16 МБ данных из памяти на диск (или наоборот) - это в тысячу раз больше, чем обычная paging-операция.
Где на практике используются большие страницы памяти? В приложениях вида: "Ты заплатил $40'000 за чудовищный сервер, единственная задача которого состоит в том, чтобы запускать МЕНЯ" - к примеру, SQL Server. Эти приложения в любом случае не хотят, чтобы эта память была бы выгружаемой, так что добавление в ОС кода, который делал бы большие страницы выгружаемыми - это не только куча работы, но также и куча работы, чтобы сделать что-то никому не нужное, что никто не будет использовать.
Более того, выделение больших страниц затратно по времени. Все физические страницы для одной большой страницы должны быть непрерывны и корректно выровнены на границу большой страницы. До Windows XP выделение одной большой страницы могло занять 15 секунд или даже больше, если ваша память была сильно фрагментирована - и даже машины с большим количеством памяти (более 2 Гб), вероятно, будут иметь фрагментированную память, если дать им поработать некоторое время. Внутренне, размещение физической памяти для большой страницы выполняется функцией ядра, задача которой состоит в поиске непрерывного участка физической памяти - такая задача часто требуется драйверам ввода-вывода. Некоторые драйверы ведут себя "крайне грубо", если их запрос на выделение непрерывного участка памяти неудачен, поэтому ОС старается очень прилежно выполнять такие запросы, даже если это потребует переноса мегабайтов другой памяти (что может также потребовать ввода-вывода с диском, для освобождения места в памяти).
Если вы следили за описанием, то должны увидеть и вторую причину, почему большие страницы не выгружаются: когда их нужно будет загрузить обратно, то у ОС может просто не оказаться непрерывного куска свободной физической памяти для этого!
В Windows Vista менеджер памяти был реорганизован так, чтобы сделать большие страницы более привлекательными для серверных приложений: запросы на большие страницы от приложений проходят через "лёгкие участки" поиска непрерывного блока физической памяти, но не проходят через "режим отчаяния", предпочитая этому просто вернуть ошибку (эта часть менеджера памяти была дополнительно улучшена в Windows Vista SP1, так что действительно тяжеловесная работа уже не нужна).
Заметьте, что флаг
MEM_LARGE_PAGES
является исключением к общему правилу, что MEM_RESERVE
только резервирует адресное пространство, а MEM_COMMIT
просит у менеджера памяти гарантию наличия страниц памяти, но само выделение физической памяти не происходит до первого обращения к страницам. Поскольку большие страницы имеют специальные требования к физической памяти, то выделение физической памяти производится сразу, поскольку иначе менеджер памяти не всегда мог бы предоставить физическую память по первому запросу.
Статья ни о чём.
ОтветитьУдалить