2010-08-09 2 views
4

Сколько памяти или других ресурсов используется для отдельного пользователя VirtualAlloc (xxxx, yyy, MEM_RESERVE, zzz)?Память (и другие ресурсы), используемые отдельным распределением VirtualAlloc

Есть ли разница в потреблении ресурсов (например, ядро ​​выгружаемого/неподкачиваемый пул), когда я выделил один большой блок, как это:

VirtualAlloc(xxxx, 1024*1024, MEM_RESERVE, PAGE_READWRITE) 

или несколько небольших блоков, например:

VirtualAlloc(xxxx, 64*1024, MEM_RESERVE, PAGE_READWRITE); 
VirtualAlloc(xxxx+1*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE); 
VirtualAlloc(xxxx+2*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE); 
... 
VirtualAlloc(xxxx+15*64*1024, 64*1024, MEM_RESERVE, PAGE_READWRITE); 

Если кто-то не знает ответа, но может предложить эксперимент, который сможет его проверить, он также будет полезен.

Мотивация заключается в том, что я хочу реализовать возвращаемую память обратно в ОС для TCMalloc под Windows. Моя идея - заменить отдельные большие вызовы VirtualAlloc, выполнив последовательность небольших (распределение гранулярности) вызовов, чтобы я мог вызвать VirtualFree для каждого из них. Я знаю, что распределение больших блоков будет медленнее, но можно ли ожидать каких-либо штрафов за потребление ресурсов?

+0

Как я не доволен нынешним единственным ответом, теперь есть щедрость. Что я ожидаю от получаемого ответа: - либо подробное описание, какие ресурсы ядра используются отдельным блоком, зарезервированным с использованием VirtualAlloc (... MEM_RESERVE ...) вызова - или подробный эксперимент по измерению ресурсов, используемых индивидуальный вызов VirtualAlloc (... MEM_RESERVE ...) или группой абонентов VirtualAlloc (... MEM_RESERVE ...) – Suma

ответ

3

Просто FYI, вы можете использовать GetProcessMemoryInfo и GlobalMemoryStatusEx для получения некоторых измерений использования памяти.

void DisplayMemoryUsageInformation() 
{ 
    HANDLE hProcess = GetCurrentProcess(); 
    PROCESS_MEMORY_COUNTERS pmc; 
    ZeroMemory(&pmc,sizeof(pmc)); 
    GetProcessMemoryInfo(hProcess,&pmc, sizeof(pmc)); 
    std::cout << "PageFaultCount:    " << pmc.PageFaultCount    << std::endl; 
    std::cout << "PeakWorkingSetSize:   " << pmc.PeakWorkingSetSize   << std::endl; 
    std::cout << "WorkingSetSize:    " << pmc.WorkingSetSize    << std::endl; 
    std::cout << "QuotaPeakPagedPoolUsage: " << pmc.QuotaPeakPagedPoolUsage << std::endl; 
    std::cout << "QuotaPagedPoolUsage:  " << pmc.QuotaPagedPoolUsage  << std::endl; 
    std::cout << "QuotaPeakNonPagedPoolUsage: " << pmc.QuotaPeakNonPagedPoolUsage << std::endl; 
    std::cout << "QuotaNonPagedPoolUsage:  " << pmc.QuotaNonPagedPoolUsage  << std::endl; 
    std::cout << "PagefileUsage:    " << pmc.PagefileUsage    << std::endl; 
    std::cout << "PeakPagefileUsage:   " << pmc.PeakPagefileUsage   << std::endl; 

    MEMORYSTATUSEX msx; 
    ZeroMemory(&msx,sizeof(msx)); 
    msx.dwLength = sizeof(msx); 
    GlobalMemoryStatusEx(&msx); 
    std::cout << "MemoryLoad:     " << msx.dwMemoryLoad    << std::endl; 
    std::cout << "TotalPhys:     " << msx.ullTotalPhys    << std::endl; 
    std::cout << "AvailPhys:     " << msx.ullAvailPhys    << std::endl; 
    std::cout << "TotalPageFile:    " << msx.ullTotalPageFile   << std::endl; 
    std::cout << "AvailPageFile:    " << msx.ullAvailPageFile   << std::endl; 
    std::cout << "TotalVirtual:    " << msx.ullTotalVirtual   << std::endl; 
    std::cout << "AvailVirtual:    " << msx.ullAvailVirtual   << std::endl; 
    std::cout << "AvailExtendedVirtual:  " << msx.ullAvailExtendedVirtual << std::endl; 
} 
0

В моем понимании таблицы страниц у вас есть куски, например. 1024 страницы, по одному слову на каждую страницу. В любом случае, это количество страниц, а не ассигнований, которые стоят. Кроме того, могут существовать другие механизмы, которые стоят «лишних» за распределение (я просто не знаю).

Still: используя VirtualFree, вы можете выбрать decommit отдельные страницы или диапазоны страниц. Для декомментированной страницы диапазон виртуальных адресов (в рамках вашего процесса) по-прежнему сохраняется, но физическая память (RAM или файл подкачки) не назначается. Вы можете позже использовать VirtualAlloc для повторной фиксации этих страниц.

Поэтому, если вам не нужно освобождать адресное пространство для других распределителей внутри вашего процесса, вы можете использовать этот механизм для выборочного запроса и возврата памяти в ОС.

[править]

Измерение
Для измерения, я хотя сравнения производительности обоих алгоритмов по одному или более типичных нагрузок (искусственный/случайный узор распределение, выделение тяжелых «реального мира «приложение и т. д.). Преимущество: вы получаете «целую историю» - ресурсы ядра, фрагментацию страницы, производительность приложений и т. Д. Недостаток: вам нужно реализовать оба алгоритма, вы не знаете причину, и вам, вероятно, нужны очень специальные случаи для измеряемой разницы, которая прилипает из шума.

Предупреждение о фрагментации адресного пространства - будьте осторожны с вашим алгоритмом возврата. При возвращении отдельных страниц к процессу в режиме «кто бы ни был свободен» у вас может быть фрагментированное адресное пространство, в котором содержится 80% свободной памяти, но не 100K его последовательных.

+0

Спасибо, но это освобождение адресного пространства, о котором я беспокоюсь. Для меня этого недостаточно. – Suma

+0

Ну ... вы можете настроить тест. дайте нам знать, что из этого выйдет. – peterchen

+0

Но что измерить и как? Как я могу измерить потребление внутренних ресурсов ядра? – Suma

0

Вы можете попробовать использовать «perfmon» и добавить счетчики (например, Memory), чтобы начать понимать, какие ресурсы используются VirtualAlloc. Вам нужно будет сделать снимок до и после звонка в VirtualAlloc.

Другим вариантом может быть отладка процесса, вызывающего вызов VirtualAlloc под WinDBG, и использование команд памяти http://windbg.info/doc/1-common-cmds.html#20_memory_heap, чтобы получить представление о том, что на самом деле происходит.

2

Нулевая или практически нулевая память используется при вызове VirtualAlloc с параметром запаса. Это просто резервирует адресное пространство внутри процесса. Память не будет использоваться, пока вы фактически не вернете адрес со страницей с помощью VirtualAlloc с параметром commit. Это по существу разница между виртуальными байтами, объемом занимаемого адресного пространства и частным байтом, количеством памяти. Оба ваших использования VirtualAlloc() зарезервируют один и тот же объем памяти, чтобы они были эквивалентны со стороны потребления ресурсов. Я предлагаю вам прочитать об этом, прежде чем решите написать свой собственный распределитель. Одним из лучших источников для этого является Марк Руссинивич. Вы должны проверить his blog. Он написал несколько записей, названных нажатием ограничений, которые охватывают некоторые из них. Если вы хотите ознакомиться с настоящими подробными подробностями, тогда вы должны прочитать его книгу (Microsoft Windows Internals). Это, безусловно, лучшая ссылка, которую я прочитал о том, как окна управляют памятью (и все остальное).

(Изменить) Дополнительная информация: Соответствующими статьями являются «Справочник по страницам» и «Таблица страниц». Согласно моей старой копии Microsoft Windows Internals ... На x86 существует один каталог страниц для каждого процесса с 1024 элементами. Существует до 512 таблиц страниц. Каждый 32-разрядный указатель, используемый в процессе, разбит на 3 части [31-22] Индекс каталога страниц, [21-12] - это индекс таблицы страниц, а [11-0] - индекс байта на странице. Когда вы используете виртуальный адрес с резервным параметром, создается запись в каталог (32 бита), а в записи таблицы страниц создается 32 бита. В это время страница не создается для зарезервированной памяти. Лучший способ увидеть эту информацию - использовать Отладчик ядра. Я бы предложил использовать LiveKD (sysinternals). Вы можете использовать liveKD без подключения удаленного компьютера, но он не позволяет проводить живую отладку. Загрузите LiveKD и выберите свой процесс. Затем вы можете запустить команду! PTE, чтобы просмотреть таблицу страниц для процесса.

Опять же, я предлагаю прочитать внутренние внутренние окна. В моей версии (4-е изд.) Есть глава (более 100 страниц), которая охватывает все это примерами для перехода через различные структуры данных в liveKD.

+0

Эффект VirtualAlloc на память, которую он резервирует/совершает, ясен. То, что я неясно, это накладные расходы. Учитывая природу VirtualAlloc, ясно, что ее накладные расходы находятся за пределами памяти, которой он управляет. До сих пор я не мог найти ничего об этом накладных расходах, даже в ресурсах SysInternals. Память резервирования и Commiting очень отличается в одном отношении - резервируя, вы создаете новый регион, совершая только изменение состояния отдельной страницы. – Suma

+0

Добавлена ​​дополнительная информация о структуре PTE и о том, как ее увидеть в LiveKD. – Mike

Смежные вопросы