{zh0}IT解决方案 底层系统 Windows下动态内存分配方式- Powered by PHPWind
Windows下动态内存分配方式 cR<fJ[*  
    更新时间:2007-09-29作者:中国IT实验室    来源:中国IT实验室 `|& O*`  
本文关键词:           :*9Wh  
                                           这里的"动态内存"包含以下两个方面的内容: ]Q)OL  
  1.内存。这里的"内存"指的是进程的虚拟内存空间。在Win32环境下,每一个进程拥有独立的,大小为4G(0x0000 0000 ~ 0xFFFF FFFF)的虚拟内存空间。 SoSb+\* @h  
  2.动态。这里的"动态"指的是进程虚拟内存空间中的动态内存区域。在一个进程的虚拟内存空间中,只有动态内存可以在运行是被应用程序自由的分配/使用/释放。 s9DYi~/,  
 在Win32环境下,我们可以使用多种方式来分配/使用/释放动态内存,这些方式包括: fuf"Ae  
1.Win32 API. 这些API包括VirtualXXX(),HeapXXX(),LocalAlloc(),GlobalAlloc()。 6mxfLlZ  
2.C Run-Time Library.这些函数包括malloc(),free()。 1K50Z.o&@  
3.C++提供的关键词new和关键词delete。 .Vvx,>>D  
 有这么多的内存分配方式,我们在学习和实际项目中编码过程中常常会为使用那种方式而感到迷惑。他们的内部实现是否相同?他们之间有什么本质的区别?他们各自的使用场合又是怎样的? 本文试图通过深入探究他们的本质,为正确理解和使用他们提供一些依据。 ,(^*+G.i  
首先,我们{zh0}从全局的高度把握他们之间的关系。这里有一张图很好的描述了他们之间的层次关系: ;+ hH  
 这张图给了我们一个全景,仅从这张图我们就可以清楚地看到他们之间的层次关系: BuXqd[;K%  
  {dy}层:Win32 API作为系统的接口,提供了一组操作虚拟内存的接口; T!)(Dv8@F  
  第二层:Heap作为虚拟内存的一部分,Win32 API又提供了一组操作Heap内存的接口,但是这些接口是建立在操作虚拟内存的接口的基础上。 VQOezQs\  
  第三层:Windows平台下的C Run-Time Library 又利用Heap API来实现malloc和free。 Ry6@VQ"NLb  
 由此我们可以看出,这些动态内存操作方式之间存有单一的层次关系,位于这个层次的{zd1}层的是Virtual MemoryAPI,可以说这些方式都是建立在Virtual Memory API的基础上。下面就从Virtual MemoryAPI开始,逐层分析他们之间的区别: U0P~  
一.Virtual Memory API uiR8,H9*M  
 作为Windows系统提供的最"核心"的对虚拟内存操作的接口,也作为其他几种方式的基础,Virtual MemoryAPI应该在几种方式中是最通用,也是功能最强大的一种方式。如果想对Virtual MemoryAPI的使用深入的了解,可以参阅《Programming Application for Windows》(By JeffreyRichter) t&e{_|i#+  
二.Heap Memory API N6i Q8P -  
 我们在学习进程内存空间"映象"的时候,也提到了"Heap"这个概念,那个时候"Heap"指的是一段由应用程序在运行时动态分配的内存段(Segment),和其他的内存段(代码段,数据段,栈段等)构成了进程的内存空间。而这里的"Heap"指的是进程拥有的一种对象(Windows中有很多对象,例如WINDOW,ICON,BRUSH),当我们创建一个Heap对象的时候,我们就可以获得这个对象的Handle,然后我们就可以使用这个handle来使用动态内存,{zh1}销毁这个对象。 8$Y9ORs4  
三.LocalAlloc/GlobalAlloc \ta?b!Y),?  
 这两个函数是Win16 API中遗留下来的两个函数,Win32 API为了保持兼容性才包含了这两个函数。这两个函数内部是通过HeapMemoryAPI来操作一个"特殊"的Heap对象:进程的默认堆对象。每一个进程在初始化的时候,都会创建一个默认的Heap对象,在进程结束的时候销毁这个默认的Heap对象。LocalAlloc和GblobalAlloc的区别仅表现在Win16环境下,在Win16环境下,内存的地址是通过段:段内偏移量来获取的,LocalAlloc()只能在同一段内分配内存,而GlobalAlloc可以跨越段边界访问内存。在Win32环境下内存访问不存在这样的限制,所以他们表现出相同的功能。由于Heap MemoryAPIxx可以实现他们两个的功能,所以在Win32下不推荐使用这两个函数。 Ao&"r[oJSv  
四.malloc/free d<P\&!R(  
 这两个函数是使用频率{zg}的两个函数,由于他们是标准C库中的一部分,所以具有极高的移植性。这里的"移植性"指的是使用他们的代码可以在不同的平台下编译通过,而不同的平台下的C Run-Time Library的具体实现是平台相关的,在Windows平台的C Run-TimeLibrary中的malloc()和free()是通过调用Heap Memory API来实现的。值得注意的是C Run-TimeLibrary拥有独立的Heap对象,我们知道,当一个应用程序初始化的时候,首先被初始化的是C Run-TimeLibrary,然后才是应用程序的入口函数,而Heap对象就是在C Run-Time Library被初始化的时候被创建的。对于动态链接的CRun-TimeLibrary,运行库只被初始化一次,而对于静态连接的运行库,每链接一次就初始化一次,所以对于每个静态链接的运行库都拥有彼此不同的Heap对象。这样在某种情况下就会出问题,导致程序崩溃,例如一个应用程序调用了多个DLL,除了一个DLL外,其他的DLL,包括应用程序本身动态连接运行库,这样他们就使用同一个Heap对象。而有一个DLL使用静态连接的运行库,它就拥有一个和其他DLL不同的Heap对象,当在其他DLL中分配的内存在这个DLL中释放时,问题就出现了。 WX3-\Y5E  
五.关键词new/关键词delete Z=vU}S>r|v  
 这两个词是C++内置的关键词(keyword)。当C++编译器看到关键词new的时候,例如: !'*-$e  
  CMyObject* pObj = new CMyObject;编译器会执行以下两个任务: T{[=oH+  
1。在堆上动态分配必要的内存。这个任务是由编译器提供的一个全局函数void* ::operator new(size_t)来完成的。值得注意的是任何一个类都可以重载这个全局函数。如果类重载了这个函数的化,被类重载的那个会被调用。 B \2 SH%\  
2。调用CMyClass的构造函数来初始化刚刚生成的对象。当然如果分配的对象是C++中的基本数据类型则不会有构造函数调用。 >}6%#CAf  
如果要深入全局函数void* ::operator new(size_t)的话,我们会发现,它的具体实现是通过调用malloc来分配内存的。 f9{Rb/l!BQ  
 有了这样的分析,我们对这些动态内存分配方式有了一个更高一级的认识,在我们的代码中就可以正确使用他们。 'm kLCS  
郑重声明:资讯 【{zh0}IT解决方案 底层系统 Windows下动态内存分配方式- Powered by PHPWind】由 发布,版权归原作者及其所在单位,其原创性以及文中陈述文字和内容未经(企业库qiyeku.com)证实,请读者仅作参考,并请自行核实相关内容。若本文有侵犯到您的版权, 请你提供相关证明及申请并与我们联系(qiyeku # qq.com)或【在线投诉】,我们审核后将会尽快处理。
—— 相关资讯 ——