统计windows crt库内存使用情况
1. 关于heap类型
From http://msdn.microsoft.com/en-us/library/wc28wkas%28v=vs.80%29.aspx
有如下几种heap block: _NORMAL_BLOCK, _CLIENT_BLOCK, _FREE_BLOCK,
关于不同heap block区别 http://msdn.microsoft.com/en-us/library/htdyz80k%28v=vs.80%29.aspx
A normal block is ordinary memory allocated by your program. A client block is a special type of memory block used by MFC programs for objects that require a destructor. The MFC new operation creates either a normal block or a client block, as appropriate for the object being created. A CRT block is a block of memory allocated by the CRT library for its own use. The CRT library handles the deallocation for these blocks, so it is unlikely you will see these in the memory leak report unless something is seriously wrong (for example, the CRT library is corrupted). A free block is a block of memory that has been released. An ignore block is a block that you have specifically marked so it doesn't appear in the memory leak report.
2. 打印当前crt heap使用情况的一段代码
inline unsigned long asm_getmemallocsize(void) { _CrtMemState stMemState; memset( &stMemState, 0, sizeof(stMemState)); // Get the allocated size _CrtMemCheckpoint( &stMemState ); return stMemState.lSizes[1]; // 1 means Normal Blocks }
3. 关于_CrtMemState中一个属性lTotalCount有bug
http://www.flounder.com/bugincrtmemcheckpoint.htm
4. 使用_heapwalk打印当前heap使用大小(俺比较奇怪跟2有啥不同?)
/**************************************************************************** * CountWalk * Result: UINT * Amount of space allocated as revealed by _heapwalk ****************************************************************************/ UINT CountWalk() { int HeapStatus; BOOL running = TRUE; _HEAPINFO info; info._pentry = NULL; UINT UsedBytes = 0; while(running) { /* scan heap */ HeapStatus = _heapwalk(&info); switch(HeapStatus) { /* check status */ case _HEAPOK: break; case _HEAPEND: running = FALSE; break; default: ASSERT(FALSE); running = FALSE; continue; } /* check status */ if(info._useflag == _USEDENTRY) { /* used block */ UsedBytes += info._size; } /* used block */ } /* scan heap */ return UsedBytes; } // CountWalk
5. 从windows系统角度,有如下几种heap类型: standard, look-aside, low-fragmentation (LFH)
msdn提供了一些函数来获取heap信息,包括有几个heap,每个heap是什么类型
// From http://msdn.microsoft.com/en-us/library/windows/desktop/ee175820%28v=vs.85%29.aspx #include <windows.h> #include <tchar.h> #include <stdio.h> #include <intsafe.h> int HeapInfo(HANDLE hHeap); int __cdecl _tmain() { DWORD NumberOfHeaps; DWORD HeapsIndex; DWORD HeapsLength; HANDLE hDefaultProcessHeap; HRESULT Result; PHANDLE aHeaps; SIZE_T BytesToAllocate; // // Retrieve the number of active heaps for the current process // so we can calculate the buffer size needed for the heap handles. // NumberOfHeaps = GetProcessHeaps(0, NULL); if (NumberOfHeaps == 0) { _tprintf(TEXT("Failed to retrieve the number of heaps with LastError %d.\n"), GetLastError()); return 1; } // // Calculate the buffer size. // Result = SIZETMult(NumberOfHeaps, sizeof(*aHeaps), &BytesToAllocate); if (Result != S_OK) { _tprintf(TEXT("SIZETMult failed with HR %d.\n"), Result); return 1; } // // Get a handle to the default process heap. // hDefaultProcessHeap = GetProcessHeap(); if (hDefaultProcessHeap == NULL) { _tprintf(TEXT("Failed to retrieve the default process heap with LastError %d.\n"), GetLastError()); return 1; } // // Allocate the buffer from the default process heap. // aHeaps = (PHANDLE)HeapAlloc(hDefaultProcessHeap, 0, BytesToAllocate); if (aHeaps == NULL) { _tprintf(TEXT("HeapAlloc failed to allocate %d bytes.\n"), BytesToAllocate); return 1; } // // Save the original number of heaps because we are going to compare it // to the return value of the next GetProcessHeaps call. // HeapsLength = NumberOfHeaps; // // Retrieve handles to the process heaps and print them to stdout. // Note that heap functions should be called only on the default heap of the process // or on private heaps that your component creates by calling HeapCreate. // NumberOfHeaps = GetProcessHeaps(HeapsLength, aHeaps); if (NumberOfHeaps == 0) { _tprintf(TEXT("Failed to retrieve heaps with LastError %d.\n"), GetLastError()); return 1; } else if (NumberOfHeaps > HeapsLength) { // // Compare the latest number of heaps with the original number of heaps. // If the latest number is larger than the original number, another // component has created a new heap and the buffer is too small. // _tprintf(TEXT("Another component created a heap between calls. ") \ TEXT("Please try again.\n")); return 1; } _tprintf(TEXT("Process has %d heaps.\n"), HeapsLength); for (HeapsIndex = 0; HeapsIndex < HeapsLength; ++HeapsIndex) { _tprintf(TEXT("Heap %d at address: %#p.\n"), HeapsIndex, aHeaps[HeapsIndex]); HeapInfo(aHeaps[HeapsIndex]); } // // Release memory allocated from default process heap. // if (HeapFree(hDefaultProcessHeap, 0, aHeaps) == FALSE) { _tprintf(TEXT("Failed to free allocation from default process heap.\n")); } return 0; } // From http://msdn.microsoft.com/en-us/library/windows/desktop/aa366703%28v=vs.85%29.aspx //#include <windows.h> //#include <tchar.h> //#include <stdio.h> #define HEAP_STANDARD 0 #define HEAP_LAL 1 #define HEAP_LFH 2 int HeapInfo(HANDLE hHeap) { ULONG HeapInformation; _tprintf(TEXT("heap at address: %#p.\n"), hHeap); // // Query heap features that are enabled. // BOOL bResult = HeapQueryInformation(hHeap, HeapCompatibilityInformation, &HeapInformation, sizeof(HeapInformation), NULL); if (bResult == FALSE) { _tprintf(TEXT("Failed to retrieve heap features with LastError %d.\n"), GetLastError()); return 1; } // // Print results of the query. // _tprintf(TEXT("HeapCompatibilityInformation is %d.\n"), HeapInformation); switch(HeapInformation) { case HEAP_STANDARD: _tprintf(TEXT("The default process heap is a standard heap.\n")); break; case HEAP_LAL: _tprintf(TEXT("The default process heap supports look-aside lists.\n")); break; case HEAP_LFH: _tprintf(TEXT("The default process heap has the low-fragmentation ") \ TEXT("heap enabled.\n")); break; default: _tprintf(TEXT("Unrecognized HeapInformation reported for the default ") \ TEXT("process heap.\n")); break; } return 0; }