VirtualAlloc MEM_COMMIT и MEM_RESERVE

Меня немного смущает VirtualAlloc,

Мы можем зарезервировать память, используя MEM_RESERVE, а затем зафиксировать ее, используя MEM_COMMIT, но я немного не понимаю, какая разница при использовании между двумя нижеприведенными функциями:

m_pvData = VirtualAlloc(NULL, m_nBuffSize, MEM_COMMIT, PAGE_READWRITE);
m_pvData = VirtualAlloc(NULL, m_nBuffSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

В чем преимущество второго выбора?

И я могу использовать функцию ниже, чтобы получить буфер:

void* pdata = VirtualAlloc(NULL, 64*1024*1024, MEM_COMMIT, PAGE_READWRITE);
if (pdata == NULL)
{
    cout<<"Last error is "<<GetLastError()<<endl;
}

ошибки нет


person user2714997    schedule 25.09.2014    source источник
comment
Потому что первое технически неверно. Вы не можете совершать без резервирования.   -  person Raymond Chen    schedule 25.09.2014
comment
Но я могу использовать функцию ниже для выделения буфера, как показано ниже: void* pdata = VirtualAlloc(NULL, 64*1024*1024, MEM_COMMIT, PAGE_READWRITE); if (pdata == NULL) { cout‹‹Последняя ошибка: ‹‹GetLastError()‹‹endl; }   -  person user2714997    schedule 25.09.2014
comment
ОС может догадаться, что вы имели в виду. Так что нет никакой разницы.   -  person Hans Passant    schedule 25.09.2014
comment
Но вы должны пройти оба. Не заставляйте ОС прикрывать свои ошибки. Когда-нибудь операционная система может перестать быть такой восприимчивой к ошибкам программирования.   -  person Raymond Chen    schedule 25.09.2014
comment
Понятно, спасибо за помощь. Оказалось, ОС хороший человек   -  person user2714997    schedule 26.09.2014


Ответы (1)


Разница вот в чем: с MEM_RESERVE вы, по сути, говорите операционной системе: «Эй, пожалуйста, мне нужен этот непрерывный блок страниц виртуальной памяти, не могли бы вы дать мне адрес памяти, который соответствует моим потребностям?»

А операционная система вычисляет, где зарезервировать ваш блок. Но он пока ничего не выделяет. (Чтобы увидеть, как это делает операционная система, просто посмотрите такие книги, как «Windows Internals 5th» Марка Руссиновича — подсказка: поищите в Google о деревьях VAD).

Итак, когда вы резервируете блок памяти, операционная система просто выделяет «узел» где-то в дереве или подобную структуру, говоря, что эти адреса зарезервированы, точно так же, как стол в ресторане, и это не может быть используется в других вызовах VirtualAlloc().

Вместо этого, когда вы фактически фиксируете страницы с помощью MEM_COMMIT, операционная система фактически выделяет страницы виртуальной памяти в блоке, который вы зарезервировали ранее. Конечно, вы можете зафиксировать страницы только в тех блоках, которые вы зарезервировали ранее. Не делать этого — все равно, что зарезервировать места в ресторане, а затем сесть за другой столик, не зарезервированный вами.

ПРИМЕЧАНИЕ. Страницы на самом деле не выделяются при их фиксации, так как вы читаете/записываете их (ошибка программной страницы). Это очень полезная оптимизация.

ПРИМЕЧАНИЕ 2: Тот факт, что вы можете ИЛИ MEM_RESERVE|MEM_COMMIT, просто полезен, поэтому вам не нужно вызывать API `VirtualAlloc()' два раза, но на самом деле это две совершенно разные операции.

ПРИМЕЧАНИЕ 3. Флаг MEM_COMMIT будет фиксировать страницы на границе размера страницы, а использование MEM_RESERVE или MEM_RESERVE|MEM_COMMIT будет резервировать или резервировать + фиксировать страницы на границе, превышающей размер страницы, обычно 64 КБ во всех версиях Windows с сегодняшнего дня. Вы можете получить этот номер, позвонив по номеру GetSystemInfo().

person Marco Pagliaricci    schedule 23.07.2015