A Review of Windows Memory Management
Windows有三种内存
stack 栈:用于分配本地变量,大小在编译时确定,分配与释放仅需移动栈指针
memory-mapped files 内存映射文件:不讨论
heap 堆:用于分配动态变量,大小在运行时确定,使用heap manager进行分配和回收
在Windows中,每个进程启动时会分配一个default heap,然后使用HeapCreate, HeapAlloc,HeapFree进行default heap的管理,访问default heap是线程安全的。
使用CRT库的函数可能会使用CRT heap,并且使用malloc和free来管理。
COM使用CoTaskMemAlloc和CoTaskMemFree来管理进程间Mashal,如[out]参数,在一个进程中创建,在另一个进程中销毁。
使用不同的堆模型,能够提高了并发性,并且减少换页。
The IAtlMemMgr Interface
__interface IAtlMemMgr { public: void* Allocate( size_t nBytes ) ; void Free( void* p ) ; void* Reallocate( void* p, size_t nBytes ) ; size_t GetSize( void* p ) ; };
The Memory Manager Classes
ATL提供了5个Heap Manger classes
Memory Manager Class | Heap Functions Used |
---|---|
CComHeap | CoTaskMemAlloc, CoTaskMemFree, CoTaskMemRealloc, IMalloc::GetSize |
CCRTHeap | malloc, free, realloc, _msize |
CLocalHeap | LocalAlloc, LocalFree, LocalReAlloc, LocalSize |
CGlobalHeap | GlobalAlloc, GlobalFree, GlobalReAlloc, GlobalSize |
CWin32Heap | HeapAlloc, HeapFree, HeapReAlloc, HeapSize |
例如:
class CComHeap : public IAtlMemMgr { // IAtlMemMgr public: virtual void* Allocate( size_t nBytes ) { #ifdef _WIN64 if( nBytes > INT_MAX ) { return( NULL ); } #endif return( ::CoTaskMemAlloc( ULONG( nBytes ) ) ); } virtual void Free( void* p ) { ::CoTaskMemFree( p ); } virtual void* Reallocate( void* p, size_t nBytes ) { #ifdef _WIN64 if( nBytes > INT_MAX ) { return( NULL ); } #endif return( ::CoTaskMemRealloc( p, ULONG( nBytes ) ) ); } virtual size_t GetSize( void* p ) { CComPtr< IMalloc > pMalloc; ::CoGetMalloc( 1, &pMalloc ); return( pMalloc->GetSize( p ) ); } };
注意,CWn32Heap与众不同,其使用Handle而不是进程堆
CWin32Heap() : m_hHeap( NULL ), m_bOwnHeap( false ) { } CWin32Heap( HANDLE hHeap ) : m_hHeap( hHeap ), m_bOwnHeap( false ) { ATLASSERT( hHeap != NULL ); } CWin32Heap( DWORD dwFlags, size_t nInitialSize, size_t nMaxSize = 0 ) : m_hHeap( NULL ), m_bOwnHeap( true ) { ATLASSERT( !(dwFlags&HEAP_GENERATE_EXCEPTIONS) ); m_hHeap = ::HeapCreate( dwFlags, nInitialSize, nMaxSize ); if( m_hHeap == NULL ) { AtlThrowLastWin32(); } }
void Attach( HANDLE hHeap, bool bTakeOwnership ) { ATLASSERT( hHeap != NULL ); ATLASSERT( m_hHeap == NULL ); m_hHeap = hHeap; m_bOwnHeap = bTakeOwnership; } HANDLE Detach() { HANDLE hHeap; hHeap = m_hHeap; m_hHeap = NULL; m_bOwnHeap = false; return( hHeap ); }
应该避免下面:
// create an instance and allocate a heap
CWin32Heap heap(0, // no exceptions, use thread-safe access
4000, // initial size
0); // no max size => heap grows as needed
// manually create a second heap
HANDLE hHeap = ::HeapCreate(0, 5000, 0);
// this is gonna get you in a "heap" of trouble!
heap.Attach(hHeap, false /* same result if true */ );
使用线程专用堆的例子:
DWORD g_dwTlsIndex; // holds thread-local storage slot index // g_dwTlsIndex = ::TlsAlloc() performed in other // initialization code // Create a private heap for use on this thread // only => no synchronized access CWin32Heap* pHeap = new CWin32Heap(HEAP_NO_SERIALIZE, 50000); // Store the heap pointer in this thread's TLS slot ::TlsSetValue(g_dwTlsIndex, reinterpret_cast<void*>( static_cast<IAtlMemMgr*>(pHeap))); // ... // Retrieve the heap pointer from TLS pHeap = (IAtlMemMgr*)::TlsGetValue(g_dwTlsIndex); // Create a new CStencil instance that uses the private heap CStencil* pStencil = new CStencil(pHeap);