Win32 内存管理
来源:互联网 发布:罗俊 中山大学 知乎 编辑:程序博客网 时间:2024/06/14 05:26
摘自《C++应用程序性能优化》
在Win32平台下,可以通过如下5组函数来使用内存(申请和释放操作等)
1. 传统的CRT函数(malloc/free系列),因为这组函数的平台无关性,如果程序会被移植到其它非Windows平台,则这组函数是首选。
2. global heap/local heap函数(GlobalAlloc/LocalAlloc系列),这组函数是为了向后兼容而保留的。在Windows 3.1平台下, global heap为系统中所有进程共有的堆,这些进程包括系统进程和用户进程。它们对此global heap内存的申请会交错在一起,从而使得一个用户进程的不小心的内存使用错误会导致整个操作系统的崩溃。local heap又被称为“private heap”,与global heap相对应,local heap为每个进程私有。进程通过LocalAlloc从自己的local heap里申请内存,而不会相互干扰。除此之外,进程不能通过另外的用户自定义堆或者其它方式动态的申请内存。到了Win32平台,由于考虑到安全因素,global heap已经废弃,local heap也改名为“process heap”。为了使得以前针对Windows 3.1平台写的应用程序能够运行在新的Win32平台上,GlobalAlloc/LocalAlloc系列函数仍然得到沿用,但是这一系列函数最后都是从process heap中分配内存。不仅如此,Win32平台还允许进程除process heap之外生成和使用新的用户自定义堆,因此在Win32平台下建议不使用GlobalAlloc/LocalAlloc系列函数进行内存操作。
3. 虚拟内存函数(VirtualAlloc/VirtualFree系列),这组函数直接通过保留(reserve)和提交(commit)虚拟内存地址空间来操作内存,因此它们为开发人员提供最大的自由度,但相应的也为开发人员内存管理工作增加了更多的负担。这组函数适合于为大型连续的数据结构数组开辟空间。
4. 内存映射文件函数(CreateFileMapping/MapViewOfFile系列),系统使用内存映射文件函数系列来加载.exe或者.dll文件。而对开发人员而言,一方面通过这组函数可以方便的操作硬盘文件,而不用考虑那些繁琐的文件I/O操作;另一方面,运行在同一台机器上的多个进程可以通过内存映射文件函数来共享数据(这也是同一台机器上进程间进行数据共享和通信的最有效率和最方便的方法)。
5. 堆内存函数(HeapCreate/HeapAlloc系列),Win32平台中的每个堆都是各进程私有的,每个进程除了默认的进程堆,还可以另外创建用户自定义堆。当程序需要动态创建多个小数据结构时,堆函数系列最适合。一般来世CRT函数(malloc/free)就是基于堆内存函数实现的。
其他:
Debugging Functions
WriteProcessMemory和ReadProcessMemroy
Inside CRT: Debug Heap Management
这是两个被核准用来读写另一个进程的内存数据的函数。为了使用他们,你必须先获得另一个进程的句柄(handle)。然而Win32 API不提供什么方便的做法,让你轻易达到这一目的。这两个函数是Win32调试器的关键函数。调试器是属于那种“必须读写其他进程内存数据”的另类软件。J
这两个函数的底层十分类似。因此我决定只展示其中一个的虚拟代码。唯一明显的差异在于WriteProcessMemory调用VWIN32的0x002A0017 Service,而ReadProcessMemory调用VWIN32的0x002A0016 Service。
WriteProcessMemory首先做同步控制。它先确定它没有持有Win16Mutex和Krn32Mutex,然后进入“必须完成”状态—意思是:不能在执行过程中被切换出来。然后确定源地址(source address)位于应用程序私有的arena中(也就是VMM文件中说的4MB-2GB之间)。
接下来WriteProcessMemory取得指针,指向源进程(source process),再从其身上获取线程链表。为了某些理由,“实际内存复制动作”的VWIN32 Service,希望获得目标进程(target process)之当前线程的ring0 stack地址。一旦所有东西都到手了,它就请求Krn32Mutex并调用VWIN32 Server。在VWIN32完成其memory context之神奇魔法后,WriteProcessMemory释放Krn32Mutex,并调用LeaveMustComplete以退出“必须完成”状态。如果这个程序中有某些事情出了错,就调用SetLastError,让调用者知道错在哪儿了。
GlobalMemoryStauts
GlobalMemoryStatus可以很方便的观察内存的状态。这个函数填充MEMORYSTATUS结构,像是有多少pages已经映射到实际的RAM、交换文件(swap file)的大小等等。这个函数很类似于Win16的MemManInfo。
GlobalMemoryStatus其实只是个参数检验层,它只确定一件事:传给函数的指针指向一块足以存放MEMORYSTATUS结构的内存。别管文件上怎么说,你不需要在调用GlobalMemoryStatus之前先初始化MEMORYSTATUS结构的dwLength成员。
原文地址:http://www.codeguru.com/cpp/w-p/win32/tutorials/article.php/c9535/
When you compile a debug build of your program with Visual Studio and run it in debugger, you can see that the memory allocated or deallocated has funny values, such as 0xCDCDCDCD or 0xDDDDDDDD. This is the result of the work Microsoft has put in to detect memory corruption and leaks in the Win32 platform. In this article, I will explain how memory allocation/deallocation is done via new/delete or malloc/free.
First, I will explain what all these values that you see, like CD, DD, and so forth, mean.
If you take a look at DBGHEAP.C, you can see how some of these values are defined:
static unsigned char _bNoMansLandFill = 0xFD; /* fill no-man's land with this */static unsigned char _bDeadLandFill = 0xDD; /* fill free objects with this */static unsigned char _bCleanLandFill = 0xCD; /* fill new objects with this */
Before going any further, take a look at the memory management function that I will refer in this article.
GlobalAllocWin32 API to allocate the specified number of bytes from the heap. Windows memory management does not provide a separate local heap and global heap.LocalFree
GlobalFreeWin32 API free the specified local memory object and invalidates its handle.HeapAllocWin32 API allocates a block of memory from a heap. The allocated memory is not movable.HeapFreeWin32 API frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function.
There are many other functions that deal with memory management. For a complete view please refer to MSDN.
Note: Because this article is about memory management in a debug build, all the references to malloc and free in the following are actually references to their debug versions, _malloc_dbg and _free_dbg.
Compile the following code and run it in the debugger, walking step by step into it to see how memory is allocated and deallocated.
int main(int argc, char* argv[]){ char *buffer = new char[12]; delete [] buffer; return 0;}
Here, 12 bytes are dynamically allocated, but the CRT allocates more than that by wrapping the allocated block with bookkeeping information. For each allocated block, the CRT keeps information in a structure called _CrtMemBlockHeader, which is declared in DBGINT.H:
#define nNoMansLandSize 4typedef struct _CrtMemBlockHeader{ struct _CrtMemBlockHeader * pBlockHeaderNext; struct _CrtMemBlockHeader * pBlockHeaderPrev; char * szFileName; int nLine; size_t nDataSize; int nBlockUse; long lRequest; unsigned char gap[nNoMansLandSize]; /* followed by: * unsigned char data[nDataSize]; * unsigned char anotherGap[nNoMansLandSize]; */} _CrtMemBlockHeader;
It stores the following information:
1 - Normal block (allocated with new/malloc)
2 - CRT blocks, allocated by CRT for its own uselRequestCounter incremented with each allocationgapA zone of 4 bytes (in the current implementation) filled with 0xFD, fencing the data block, of nDataSize bytes. Another block filled with 0xFD of the same size follows the data.
Most of the work of heap block allocation and deallocation are made by HeapAlloc() and HeapFree(). When you request 12 bytes to be allocated on the heap, malloc() will call HeapAlloc(), requesting 36 more bytes.
blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;
malloc requests space for the 12 bytes we need (nSize), plus 32 bytes for the _CrtMemBlockHeader structure and another nNoMansLandSize bytes (4 bytes) to fence the data zone and close the gap.
But, HeapAlloc() will allocate even more bytes: 8 bytes below the requested block (that is, at a lower address) and 32 above it (that is, at a bigger address). It also initializes the requested block to 0xBAADF00D (bad food).
Then, malloc() fills the _CrtMemBlockHeader block with information and initializes the data block with 0xCD and no mans land with 0xFD.
Here is a table that shows how memory looks after the call to HeapAlloc() and after malloc() returns. For a complete situation, see the last table. (Note: All values are in hex.)
00320FDC
00320FE0
00320FE4
00320FE8
00320FEC
00320FF0
00320FF4
00320FF8
00320FFC
00321000
00321004
00321008
0032100C
00321010
00321014
00321018
0032101C
00321020
00321024
00321028
0032102C 09 00 09 01
E8 07 18 00
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
AB AB AB AB
AB AB AB AB
00 00 00 00
00 00 00 00
79 00 09 00
EE 04 EE 00
40 05 32 00
40 05 32 00 09 00 09 01
E8 07 18 00
98 07 32 00
00 00 00 00
00 00 00 00
00 00 00 00
0C 00 00 00
01 00 00 00
2E 00 00 00
FD FD FD FD
CD CD CD CD
CD CD CD CD
CD CD CD CD
FD FD FD FD
AB AB AB AB
AB AB AB AB
00 00 00 00
00 00 00 00
79 00 09 00
EE 04 EE 00
40 05 32 00
40 05 32 00
Colors:
- Green: win32 bookkeeping info
- Blue: block size requested by malloc and filled with bad food
- Magenta: _CrtMemBlockHeader block
- Red: no mans land
- Black: requested data block
In this example, after the call to malloc() returns, buffer will point to memory address 0x00321000.
When you call delete/free, the CRT will set the block it requested from HeapAlloc() to 0xDD, indicating this is a free zone. Normally after this, free() will call HeapFree() to give back the block to the Win32 heap, in which case the block will be overwritten with 0xFEEEEEEE, to indicate Win32 heap free memory.
You can avoid this by using the CRTDBG_DELAY_FREE_MEM_DF flag to _CrtSetDbgFlag(). It prevents memory from actually being freed, as for simulating low-memory conditions. When this bit is on, freed blocks are kept in the debug heap's linked list but are marked as _FREE_BLOCK. This is useful if you want to detect dangling pointers errors, which can be done by verifying if the freed block is written with 0xDD pattern or something else. Use _CrtCheckMemory() to verify the heap.s integrity.
The next table shows how the memory looks during the free(), before HeapFree() is called and afterwards.
00320FDC
00320FE0
00320FE4
00320FE8
00320FEC
00320FF0
00320FF4
00320FF8
00320FFC
00321000
00321004
00321008
0032100C
00321010
00321014
00321018
0032101C
00321020
00321024
00321028
0032102C 09 00 09 01
5E 07 18 00
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
AB AB AB AB
AB AB AB AB
00 00 00 00
00 00 00 00
79 00 09 00
EE 04 EE 00
40 05 32 00
40 05 32 00 82 00 09 01
5E 04 18 00
E0 2B 32 00
78 01 32 00
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
Colors:
- Green: win32 bookkeeping info
- Blue: CRT block filled with dead memory
- Gray: memory given back to win32 heap
The two tables above are put in a single, more detailed, table below:
About the Author
Marius Bancila is a Microsoft MVP for VC++. He works as a software developer for a Norwegian-based company. He is mainly focused on building desktop applications with MFC and VC#. He keeps a blog at www.mariusbancila.ro/blog, focused on Windows programming. In July 2007 together with two other Romanian MVPs he created codexpert.ro, a community for Romanian C++/VC++ programmers.
- Win32 内存管理
- Win32内存管理
- 第九章:Win32内存管理
- Win32汇编——内存管理
- win32 24内存管理和文件操作
- WIN32汇编: 12.内存管理和文件输入输出
- Win32汇编学习笔记——内存管理
- 一个Win32 C++ 动态连接库的模板 --- 调用方可管理DLL分配的内存
- 一个Win32 C++ 动态连接库的模板 — 调用方可管理DLL分配的内存
- win32内存对齐原则
- win32进程共享内存
- Win32内存结构
- Win32 内存对齐
- win32(8)--内存映射
- win32创建共享内存
- (转载)win32虚拟内存管理
- Win32 API 窗口管理
- Win32程序检查内存泄露
- wince6下6410的I2C驱动问题
- JDK1.5+Tomcat5+MySql+Juddi 架设UDDI服务器
- IT销售之道和做生意十忌
- checkbo选择多个删除
- js 写的日历组件
- Win32 内存管理
- 让人震撼惊讶的85句话!
- 经典创业论
- S3C6410的IIS驱动修改
- 基于C#开发Windows Mobile应用中短信发送功能
- IT人生畅想
- C++中类声明的内存分配
- 民族的金山与不说实话的金山
- DataTable对象重组时,错误提示“该行已经属于另一个表”