Я годами работал разработчиком встроенного ПО, в котором утечки памяти (даже минимальные объемы памяти) часто были действительно критическими.
В этих средах обычно можно было оценить количество использованногокуча, и это сделало возможным, по крайней мере, элементарную / грубую отладку утечки памяти, просто печатая общий объем используемой памяти в ключевых точках кода.
Теперь я разрабатываю синтаксический анализатор C ++ в среде Windows и... удивительно, я не могу найти способ отследить эту основную информацию. Итак, вопрос: как я могу это сделать?
Прежде чем ответить, позвольте мне сказать, что по некоторым причинам Меня не интересуют инструменты, подобные Valgrind .
Дозадавая новый вопрос, я прочитал много предыдущих вопросов, таких как:
Как получить использование памяти под Windows в C ++
Какой член вСтруктура PROCESS_MEMORY_COUNTERS дает текущую используемую память
Как определить потребление ресурсов процессора и памяти внутри процесса?
Но ни один из них не предоставил решения, подходящего для моегонеобходимо. Поэтому я решил написать новый вопрос, в котором проясните (1), что именно мне нужно, и (2) попытку, которую я уже предпринял, пытаясь достичь своей цели. По этой причине ниже я предоставляю минимальный пример программы, в которой я выполняю выделение 128 КБ (0x20000 байт) (различными способами), а затем выполняю соответствующий выпуск памяти. После каждого шага я вызываю утилиту debugMemory()
, которая печатает каждое поле структуры PROCESS_MEMORY_COUNTERS_EX
:
#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#define ONE_K 1024
static void debugMemory( const char * header )
{
PROCESS_MEMORY_COUNTERS_EX pmc;
if( header )
{
printf("%s:\t\tGetProcessMemoryInfo() returned %d\n", header, GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)));
printf("%s:\tPageFaultCount\t\t\t= %d 0x%08X\n", header, pmc.PageFaultCount, pmc.PageFaultCount);
printf("%s:\tPeakWorkingSetSize\t\t= %d 0x%08X\n", header, pmc.PeakWorkingSetSize, pmc.PeakWorkingSetSize);
printf("%s:\tWorkingSetSize\t\t\t= %d 0x%08X\n", header, pmc.WorkingSetSize, pmc.WorkingSetSize);
printf("%s:\tQuotaPeakPagedPoolUsage\t\t= %d 0x%08X\n", header, pmc.QuotaPeakPagedPoolUsage, pmc.QuotaPeakPagedPoolUsage);
printf("%s:\tQuotaPagedPoolUsage\t\t= %d 0x%08X\n", header, pmc.QuotaPagedPoolUsage, pmc.QuotaPagedPoolUsage);
printf("%s:\tQuotaPeakNonPagedPoolUsage\t= %d 0x%08X\n", header, pmc.QuotaPeakNonPagedPoolUsage, pmc.QuotaPagedPoolUsage);
printf("%s:\tQuotaNonPagedPoolUsage\t\t= %d 0x%08X\n", header, pmc.QuotaNonPagedPoolUsage, pmc.QuotaNonPagedPoolUsage);
printf("%s:\tPagefileUsage\t\t\t= %d 0x%08X\n", header, pmc.PagefileUsage, pmc.PagefileUsage);
printf("%s:\tPeakPagefileUsage\t\t= %d 0x%08X\n", header, pmc.PeakPagefileUsage, pmc.PeakPagefileUsage);
printf( "%s:\tPrivateUsage\t\t\t= %d 0x%08X\n", header, pmc.PrivateUsage, pmc.PrivateUsage );
}
}
int main(void)
{
/* Initial */
debugMemory("INI");
Sleep(5000);
/* Malloc */
char *p1 = (char *) malloc(128 * ONE_K);
debugMemory("MALLOC");
Sleep(5000);
/* New */
char *p2 = new char[128 * ONE_K];
debugMemory("NEW");
Sleep(5000);
/* Free */
free( p1 );
debugMemory("FREE");
Sleep(5000);
/* Delete */
delete[] p2;
debugMemory("DELETE");
return 0;
}
Согласно большинству ответов на вопросы SO, поля WorkingSetSize
и PrivateUsage
были лучшими кандидатамиза предоставление необходимой мне информации. В любом случае, просто для того, чтобы предоставить полный сценарий, я публикую результаты для всех них:
INI: GetProcessMemoryInfo() returned 1
INI: PageFaultCount = 766 0x000002FE
INI: PeakWorkingSetSize = 2834432 0x002B4000
INI: WorkingSetSize = 2830336 0x002B3000
INI: QuotaPeakPagedPoolUsage = 22448 0x000057B0
INI: QuotaPagedPoolUsage = 22448 0x000057B0
INI: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
INI: QuotaNonPagedPoolUsage = 4480 0x00001180
INI: PagefileUsage = 1069056 0x00105000
INI: PeakPagefileUsage = 1069056 0x00105000
INI: PrivateUsage = 1069056 0x00105000
MALLOC: GetProcessMemoryInfo() returned 1
MALLOC: PageFaultCount = 794 0x0000031A
MALLOC: PeakWorkingSetSize = 2949120 0x002D0000
MALLOC: WorkingSetSize = 2945024 0x002CF000
MALLOC: QuotaPeakPagedPoolUsage = 22448 0x000057B0
MALLOC: QuotaPagedPoolUsage = 22448 0x000057B0
MALLOC: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
MALLOC: QuotaNonPagedPoolUsage = 4480 0x00001180
MALLOC: PagefileUsage = 1204224 0x00126000
MALLOC: PeakPagefileUsage = 1204224 0x00126000
MALLOC: PrivateUsage = 1204224 0x00126000
NEW: GetProcessMemoryInfo() returned 1
NEW: PageFaultCount = 797 0x0000031D
NEW: PeakWorkingSetSize = 2961408 0x002D3000
NEW: WorkingSetSize = 2957312 0x002D2000
NEW: QuotaPeakPagedPoolUsage = 22448 0x000057B0
NEW: QuotaPagedPoolUsage = 22448 0x000057B0
NEW: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
NEW: QuotaNonPagedPoolUsage = 4480 0x00001180
NEW: PagefileUsage = 1339392 0x00147000
NEW: PeakPagefileUsage = 1339392 0x00147000
NEW: PrivateUsage = 1339392 0x00147000
FREE: GetProcessMemoryInfo() returned 1
FREE: PageFaultCount = 797 0x0000031D
FREE: PeakWorkingSetSize = 2961408 0x002D3000
FREE: WorkingSetSize = 2957312 0x002D2000
FREE: QuotaPeakPagedPoolUsage = 22448 0x000057B0
FREE: QuotaPagedPoolUsage = 22448 0x000057B0
FREE: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
FREE: QuotaNonPagedPoolUsage = 4480 0x00001180
FREE: PagefileUsage = 1339392 0x00147000
FREE: PeakPagefileUsage = 1339392 0x00147000
FREE: PrivateUsage = 1339392 0x00147000
DELETE: GetProcessMemoryInfo() returned 1
DELETE: PageFaultCount = 797 0x0000031D
DELETE: PeakWorkingSetSize = 2961408 0x002D3000
DELETE: WorkingSetSize = 2957312 0x002D2000
DELETE: QuotaPeakPagedPoolUsage = 22448 0x000057B0
DELETE: QuotaPagedPoolUsage = 22448 0x000057B0
DELETE: QuotaPeakNonPagedPoolUsage = 4864 0x000057B0
DELETE: QuotaNonPagedPoolUsage = 4480 0x00001180
DELETE: PagefileUsage = 1339392 0x00147000
DELETE: PeakPagefileUsage = 1339392 0x00147000
DELETE: PrivateUsage = 1339392 0x00147000
Давайте подведем итог, что мы можем понять из этих результатов:
PrivateUsage
кажетсячтобы найти поле, которое я ищу: после каждого выделения его значение увеличивается на 0x21000 (вместо 0x20000. Но я могу простить эти 0x1000 байтов служебных данных) - Его значение ISN'T уменьшилось после освобождения памяти (!!!)
- Я бы ожидал, что неиспользованная виртуальная память вернется в ОС через некоторое время (поэтому я попытался вставить 5sспит после каждого шага) но кажется, что я был не прав
WorkingSetSize
, кажется, также растет после каждого распределения, но количество грязи непоследовательно, насколько я понимаю
Любая помощь будет очень признательна. Я открыт как для любой функции magic , которую не смог найти, так и для любого обходного трюка (например, что-то, заставляющее использовать виртуальную память, показанную PrivateUsage
, для обновления).