VirtualLock
остается бездействующим (из-за ошибки)
Я пытался воспроизвести это, но это сработало, как и следовало ожидать.Выполнение примера кода, показанного внизу этого поста:
- запуск приложения (523 ошибки страницы)
- настройка размера рабочего набора (21 ошибка страницы)
VirtualAlloc
с MEM_COMMIT
2500 МБ ОЗУ (2 ошибки страницы) VirtualLock
все это ( около 641 250 страниц ошибок ) - выполняет запись для всехэтой оперативной памяти в бесконечном цикле (ошибки нулевой страницы)
Все это работает в значительной степени, как и ожидалось.2500 МБ ОЗУ - это 640 000 страниц.Числа складываются.Кроме того, что касается счетчиков оперативной памяти в масштабе всей ОС, то объем фиксации увеличивается на VirtualAlloc
, а использование физической памяти увеличивается на VirtualLock
.
Так что VirtualLock
определенно не не работает на моей машине с Win7 x64.Если я этого не сделаю, то страницы с ошибками, как и ожидалось, сместятся туда, где я начинаю запись в ОЗУ.Они по-прежнему составляют чуть более 640 000.Кроме того, первое время записи в память занимает больше времени.
Скорее, как кажется, каждая страница, к которой обращались, создается при сбое, даже если она была заблокирована ранее.
Это не неправильно .Нет гарантии, что доступ к заблокированной и разблокированной странице не будет ошибочным.Вы блокируете его, он отображается в физической памяти.Вы разблокируете его, и вы можете быть мгновенно отключенным, что делает возможной ошибку.Вы можете надеяться, что он останется на карте, но никаких гарантий ...
Что бы это ни стоило, в моей системе с несколькими гигабайтами свободной оперативной памяти это работает так, как вы надеялись: даже если я буду следоватьmy VirtualLock
с немедленным VirtualUnlock
и установкой минимального размера рабочего набора обратно на что-то маленькое, больше никаких сбоев страницы не происходит.
Вот что я сделал.Я запустил тестовую программу (ниже) с кодом и без него, который немедленно разблокирует память и восстанавливает разумный минимальный размер рабочего набора, а затем принудительно исчерпал физическую память в каждом сценарии.Прежде чем принудить к снижению объема оперативной памяти, ни одна из программ не получает ошибок страницы.После принудительного уменьшения объема ОЗУ программа, которая удерживает память заблокированной, сохраняет свой огромный рабочий набор и не имеет дальнейших сбоев страниц.Однако программа, которая разблокировала память, начинает получать ошибки страниц.
Это легче всего наблюдать, если сначала приостановить процесс, так как в противном случае постоянные записи в память сохранят все это в рабочем наборе, даже если память не установлена.не заперт (очевидно, желательная вещь).Но приостановите процесс, принудительно установите низкий объем ОЗУ и наблюдайте, как рабочий набор сокращается только для программы, которая разблокировала ОЗУ.Возобновите процесс и станьте свидетелем сбоя страниц.
Другими словами, по крайней мере, в Win7 x64 все работает точно так, как вы ожидали, используя код, представленный ниже.
Однако есть две проблемы с изменением размера WS.Во-первых, у вас обычно не должно быть гигабайта минимального рабочего набора в процессе
Ну ... если вы хотите VirtualLock
, вы уже вмешиваетесь в него.Единственное, что делает SetProcessWorkingSetSize
, это позволяет вам вмешиваться.Это не ухудшает производительность само по себе;это VirtualLock
, что делает - но только если в системе фактически не хватает физической памяти.
Вот полная программа:
#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
SIZE_T chunkSize = 2500LL * 1024LL * 1024LL; // 2,626,568,192 = 640,000 pages
int sleep = 5000;
Sleep(sleep);
cout << "Setting working set size... ";
if (!SetProcessWorkingSetSize(GetCurrentProcess(), chunkSize + 5001001L, chunkSize * 2))
return -1;
cout << "done" << endl;
Sleep(sleep);
cout << "VirtualAlloc... ";
UINT8* data = (UINT8*) VirtualAlloc(NULL, chunkSize, MEM_COMMIT, PAGE_READWRITE);
if (data == NULL)
return -2;
cout << "done" << endl;
Sleep(sleep);
cout << "VirtualLock... ";
if (VirtualLock(data, chunkSize) == 0)
return -3;
//if (VirtualUnlock(data, chunkSize) == 0) // enable or disable to experiment with unlocks
// return -3;
//if (!SetProcessWorkingSetSize(GetCurrentProcess(), 5001001L, chunkSize * 2))
// return -1;
cout << "done" << endl;
Sleep(sleep);
cout << "Writes to the memory... ";
while (true)
{
int* end = (int*) (data + chunkSize);
for (int* d = (int*) data; d < end; d++)
*d = (int) d;
cout << "done ";
}
return 0;
}
Обратите внимание, что этот код помещает поток вспать после VirtualLock
.Согласно сообщению 2007 Раймонда Чена , операционная система может свободно выгружать все данные из физической памяти на этом этапе и до тех пор, пока поток не проснется снова.Также обратите внимание, что MSDN утверждает иначе , говоря, что эта память не будет выгружена, независимо от того, все ли потоки спят или нет.В моей системе они, конечно, остаются в физической памяти, пока единственный поток спит.Я подозреваю, что совет Рэймонда был применен в 2007 году, но больше не верен в Win7.