Память (и другие ресурсы), используемая для отдельного выделения VirtualAlloc - PullRequest
4 голосов
/ 09 августа 2010

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

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

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 для каждого из них.Я знаю, что таким образом распределение больших блоков будет медленнее, но можно ли ожидать каких-либо штрафов за потребление ресурсов?

Ответы [ 4 ]

3 голосов
/ 18 августа 2010

Только к сведению, вы можете использовать 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;
}
2 голосов
/ 19 августа 2010

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

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

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

0 голосов
/ 16 августа 2010

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

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

0 голосов
/ 09 августа 2010

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

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

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

[править]

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...