📄 mfc10.php
字号:
<HTML><HEAD><TITLE>MFC教程_ 内存分配方式和调试机制</TITLE>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<META content="MSHTML 6.00.2800.1458" name=GENERATOR></HEAD>
<BODY bgColor=#ffffff>
<OL start=10>
<P align=justify>
<LI><A name=_Toc445889121></A><A name=_Toc445782524></A><A
name=_Toc452640983></A><A name=_Toc457299092></A><B>内存分配方式和调试机制</B>
<P></P>
<OL>
<P align=justify>
<LI><B><A name=_Toc445889122></A><A name=_Toc445782525></A><A
name=_Toc452640984></A><A name=_Toc457299093></A>M内存分配</B>
<P></P>
<OL>
<P align=justify>
<LI><B><A name=_Toc445889123></A><A name=_Toc445782526></A><A
name=_Toc452640985></A><A name=_Toc457299094></A>内存分配函数</B>
<P></P></LI></OL></LI></OL></LI></OL>
<P align=justify>MFCWin32或者C语言的内存分配API,有四种内存分配API可供使用。</P>
<OL>
<P align=justify>
<LI>Win32的堆分配函数
<P></P>
<P
align=justify>每一个进程都可以使用堆分配函数创建一个私有的堆──调用进程地址空间的一个或者多个页面。DLL创建的私有堆必定在调用DLL的进程的地址空间内,只能被调用进程访问。</P>
<P
align=justify>HeapCreate用来创建堆;HeapAlloc用来从堆中分配一定数量的空间,HeapAlloc分配的内存是不能移动的;HeapSize可以确定从堆中分配的空间的大小;HeapFree用来释放从堆中分配的空间;HeapDestroy销毁创建的堆。</P>
<P align=justify></P>
<LI>Windows传统的全局或者局部内存分配函数
<P></P>
<P
align=justify>由于Win32采用平面内存结构模式,Win32下的全局和局部内存函数除了名字不同外,其他完全相同。任一函数都可以用来分配任意大小的内存(仅仅受可用物理内存的限制)。用法可以和Win16下基本一样。</P>
<P align=justify>Win32下保留这类函数保证了和Win16的兼容。</P>
<P align=justify></P>
<LI>C语言的标准内存分配函数
<P></P>
<P align=justify>C语言的标准内存分配函数包括以下函数:</P>
<P align=justify>malloc,calloc,realloc,free,等。</P>
<P align=justify>这些函数最后都映射成堆API函数,所以,malloc分配的内存是不能移动的。这些函数的调式版本为</P>
<P align=justify>malloc_dbg,calloc_dbg,realloc_dbg,free_dbg,等。</P>
<P align=justify></P>
<LI>Win32的虚拟内存分配函数
<P></P></LI></OL>
<P
align=justify>虚拟内存API是其他API的基础。虚拟内存API以页为最小分配单位,X86上页长度为4KB,可以用GetSystemInfo函数提取页长度。虚拟内存分配函数包括以下函数:</P>
<UL>
<P align=justify>
<LI>LPVOID VirtualAlloc(LPVOID lpvAddress,
<P></P></LI></UL>
<DIR>
<P align=justify>DWORD cbSize,</P>
<P align=justify>DWORD fdwAllocationType,</P>
<P align=justify>DWORD fdwProtect);</P></DIR>
<P
align=justify>该函数用来分配一定范围的虚拟页。参数1指定起始地址;参数2指定分配内存的长度;参数3指定分配方式,取值MEM_COMMINT或者MEM_RESERVE;参数4指定控制访问本次分配的内存的标识,取值为PAGE_READONLY、PAGE_READWRITE或者PAGE_NOACCESS。</P>
<UL>
<P align=justify>
<LI>LPVOID VirtualAllocEx(HANDLE process,
<P></P></LI></UL>
<DIR>
<P align=justify>LPVOID lpvAddress,</P>
<P align=justify>DWORD cbSize,</P>
<P align=justify>DWORD fdwAllocationType,</P>
<P align=justify>DWORD fdwProtect);</P></DIR>
<P
align=justify>该函数功能类似于VirtualAlloc,但是允许指定进程process。VirtaulFree、VirtualProtect、VirtualQuery都有对应的扩展函数。</P>
<UL>
<P align=justify>
<LI>BOOL VirtualFree(LPVOID lpvAddress,
<P></P></LI></UL>
<DIR>
<P align=justify>DWORD dwSize,</P>
<P align=justify>DWORD dwFreeType);</P></DIR>
<P
align=justify>该函数用来回收或者释放分配的虚拟内存。参数1指定希望回收或者释放内存的基地址;如果是回收,参数2可以指向虚拟地址范围内的任何地方,如果是释放,参数2必须是VirtualAlloc返回的地址;参数3指定是否释放或者回收内存,取值为MEM_DECOMMINT或者MEM_RELEASE。</P>
<UL>
<P align=justify>
<LI>BOOL VirtualProtect(LPVOID lpvAddress,
<P></P></LI></UL>
<DIR>
<P align=justify>DWORD cbSize,</P>
<P align=justify>DWORD fdwNewProtect,</P>
<P align=justify>PDWORD pfdwOldProtect);</P></DIR>
<P
align=justify>该函数用来把已经分配的页改变成保护页。参数1指定分配页的基地址;参数2指定保护页的长度;参数3指定页的保护属性,取值PAGE_READ、PAGE_WRITE、PAGE_READWRITE等等;参数4用来返回原来的保护属性。</P>
<UL>
<P align=justify>
<LI>DWORD VirtualQuery(LPCVOID lpAddress,
<P></P></LI></UL>
<DIR>
<P align=justify>PMEMORY_BASIC_INFORMATION lpBuffer,</P>
<P align=justify>DWORD dwLength</P>
<P align=justify>);</P></DIR>
<P
align=justify>该函数用来查询内存中指定页的特性。参数1指向希望查询的虚拟地址;参数2是指向内存基本信息结构的指针;参数3指定查询的长度。</P>
<P align=justify></P>
<UL>
<P align=justify>
<LI>BOOL VirtualLock(LPVOID lpAddress,DWORD dwSize);
<P></P></LI></UL>
<P align=justify>该函数用来锁定内存,锁定的内存页不能交换到页文件。参数1指定要锁定内存的起始地址;参数2指定锁定的长度。</P>
<UL>
<P align=justify>
<LI>BOOL VirtualUnLock(LPVOID lpAddress,DWORD dwSize);
<P></P></LI></UL>
<P align=justify>参数1指定要解锁的内存的起始地址;参数2指定要解锁的内存的长度。</P>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889124></A><A name=_Toc445782527></A><A
name=_Toc452640986></A><A name=_Toc457299095></A><B>C++的new 和
delete操作符</B>
<P></P></LI></OL></OL></OL>
<P
align=justify>MFC定义了两种作用范围的new和delete操作符。对于new,不论哪种,参数1类型必须是size_t,且返回void类型指针。</P>
<OL>
<P align=justify>
<LI>全局范围内的new和delete操作符
<P></P>
<P align=justify>原型如下:</P>
<P align=justify>void _cdecl ::operator new(size_t nSize);</P>
<P align=justify>void __cdecl operator delete(void* p);</P>
<P align=justify>调试版本:</P>
<P align=justify>void* __cdecl operator new(size_t nSize, int nType, </P>
<P align=justify>LPCSTR lpszFileName, int nLine)</P>
<P align=justify></P>
<LI>类定义的new和delete操作符
<P></P></LI></OL>
<P align=justify>原型如下:</P>
<P align=justify>void* PASCAL classname::operator new(size_t nSize);</P>
<P align=justify>void PASCAL classname::operator delete(void* p);</P>
<P align=justify>类的operator new操作符是类的静态成员函数,对该类的对象来说将覆盖全局的operator
new。全局的operator new用来给内部类型对象(如int)、没有定义operator new操作符的类的对象分配内存。</P>
<P align=justify>new操作符被映射成malloc或者malloc_dbg,delete被映射成free或者free_dbg。</P>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889125></A><A name=_Toc445782528></A><A
name=_Toc452640987></A><A name=_Toc457299096></A><B>调试手段</B>
<P></P>
<P align=justify>MFC应用程序可以使用C运行库的调试手段,也可以使用MFC提供的调试手段。两种调试手段分别论述如下。</P>
<OL>
<P align=justify>
<LI><A name=_Toc445889126></A><A name=_Toc445782529></A><A
name=_Toc452640988></A><A name=_Toc457299097></A><B>C运行库提供和支持的调试功能</B>
<P></P></LI></OL></LI></OL></OL>
<P align=justify>C运行库提供和支持的调试功能如下:</P>
<OL>
<P align=justify>
<LI>调试信息报告函数
<P></P>
<P align=justify>用来报告应用程序的调试版本运行时的警告和出错信息。包括:</P>
<P align=justify>_CrtDbgReport 用来报告调试信息;</P>
<P align=justify>_CrtSetReportMode 设置是否警告、出错或者断言信息;</P>
<P align=justify>_CrtSetReportFile 设置是否把调试信息写入到一个文件。</P>
<P align=justify></P>
<LI>条件验证或者断言宏:
<P></P>
<P align=justify>断言宏主要有:</P>
<P align=justify>assert 检验某个条件是否满足,不满足终止程序执行。</P>
<P align=justify>验证函数主要有:</P>
<P align=justify>_CrtIsValidHeapPointer 验证某个指针是否在本地堆中;</P>
<P align=justify>_CrtIsValidPointer 验证指定范围的内存是否可以读写;</P>
<P align=justify>_CrtIsMemoryBlock 验证某个内存块是否在本地堆中。</P>
<P align=justify></P>
<LI>内存(堆)调试:
<P></P></LI></OL>
<DIR>
<P align=justify>malloc_dbg
分配内存时保存有关内存分配的信息,如在什么文件、哪一行分配的内存等。有一系列用来提供内存诊断的函数:</P></DIR>
<P align=justify><B>_</B>CrtMemCheckpoint 保存内存快照在一个_CrtMemState结构中;</P>
<P align=justify>_CrtMemDifference 比较两个_CrtMemState;</P>
<P align=justify>_CrtMemDumpStatistics 转储输出一_CrtMemState结构的内容;</P>
<P align=justify>_CrtMemDumpAllObjectsSince 输出上次快照或程序开始执行以来在堆中分配的所有对象的信息;</P>
<P align=justify>_CrtDumpMemoryLeaks 检测程序执行以来的内存漏洞,如果有漏洞则输出所有分配的对象。</P>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889127></A><A name=_Toc445782530></A><A
name=_Toc452640989></A><A name=_Toc457299098></A><B>MFC提供的调试手段</B>
<P></P></LI></OL></OL></OL>
<P align=justify>MFC在C运行库提供和支持的调试功能基础上,设计了一些类、函数等来协助调试。</P>
<OL>
<P align=justify>
<LI>MFC的TRACE、ASSERT
<P></P>
<P align=justify>ASSERT</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -