电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

Windows下动态内存分配方式


发布日期:2021/3/6
 

这里的动态内存包含以下两个方面的内容

内存这里的内存指的是进程的虚拟内存空间在Win环境下每一个进程拥有独立的大小为G(x ~ xFFFF FFFF)的虚拟内存空间

动态这里的动态指的是进程虚拟内存空间中的动态内存区域在一个进程的虚拟内存空间中只有动态内存可以在运行是被应用程序自由的分配/使用/释放

在Win环境下我们可以使用多种方式来分配/使用/释放动态内存这些方式包括

Win API 这些API包括VirtualXXX()HeapXXX()LocalAlloc()GlobalAlloc()

C RunTime Library这些函数包括malloc()free()

C++提供的关键词new和关键词delete

有这么多的内存分配方式我们在学习和实际项目中编码过程中常常会为使用那种方式而感到迷惑他们的内部实现是否相同?他们之间有什么本质的区别?他们各自的使用场合又是怎样的? 本文试图通过深入探究他们的本质为正确理解和使用他们提供一些依据

首先我们最好从全局的高度把握他们之间的关系这里有一张图很好的描述了他们之间的层次关系

这张图给了我们一个全景仅从这张图我们就可以清楚地看到他们之间的层次关系

第一层Win API作为系统的接口提供了一组操作虚拟内存的接口

第二层Heap作为虚拟内存的一部分Win API又提供了一组操作Heap内存的接口但是这些接口是建立在操作虚拟内存的接口的基础上

第三层Windows平台下的C RunTime Library 又利用Heap API来实现malloc和free

由此我们可以看出这些动态内存操作方式之间存有单一的层次关系位于这个层次的最低层的是Virtual Memory API可以说这些方式都是建立在Virtual Memory API的基础上下面就从Virtual Memory API开始逐层分析他们之间的区别

Virtual Memory API

作为Windows系统提供的最核心的对虚拟内存操作的接口也作为其他几种方式的基础Virtual Memory API应该在几种方式中是最通用也是功能最强大的一种方式如果想对Virtual Memory API的使用深入的了解可以参阅《Programming Application for Windows》(By Jeffrey Richter)

Heap Memory API

我们在学习进程内存空间映象的时候也提到了Heap这个概念那个时候Heap指的是一段由应用程序在运行时动态分配的内存段(Segment)和其他的内存段(代码段数据段栈段等)构成了进程的内存空间而这里的Heap指的是进程拥有的一种对象(Windows中有很多对象例如WINDOWICONBRUSH)当我们创建一个Heap对象的时候我们就可以获得这个对象的Handle然后我们就可以使用这个handle来使用动态内存最后销毁这个对象

LocalAlloc/GlobalAlloc

这两个函数是Win API中遗留下来的两个函数Win API为了保持兼容性才包含了这两个函数这两个函数内部是通过Heap Memory API来操作一个特殊的Heap对象进程的默认堆对象每一个进程在初始化的时候都会创建一个默认的Heap对象在进程结束的时候销毁这个默认的Heap对象LocalAlloc和GblobalAlloc的区别仅表现在Win环境下在Win环境下内存的地址是通过段:段内偏移量来获取的LocalAlloc()只能在同一段内分配内存而GlobalAlloc可以跨越段边界访问内存 在Win环境下内存访问不存在这样的限制所以他们表现出相同的功能由于Heap Memory API完全可以实现他们两个的功能所以在Win下不推荐使用这两个函数

malloc/free

这两个函数是使用频率最高的两个函数由于他们是标准C库中的一部分所以具有极高的移植性这里的移植性指的是使用他们的代码可以在不同的平台下编译通过而不同的平台下的C RunTime Library的具体实现是平台相关的在Windows平台的C RunTime Library中的malloc()和free()是通过调用Heap Memory API来实现的值得注意的是C RunTime Library拥有独立的Heap对象我们知道当一个应用程序初始化的时候首先被初始化的是C RunTime Library然后才是应用程序的入口函数而Heap对象就是在C RunTime Library被初始化的时候被创建的对于动态链接的C RunTime Library运行库只被初始化一次而对于静态连接的运行库每链接一次就初始化一次所以对于每个静态链接的运行库都拥有彼此不同的Heap 对象这样在某种情况下就会出问题导致程序崩溃例如一个应用程序调用了多个DLL除了一个DLL外其他的DLL包括应用程序本身动态连接运行库这样他们就使用同一个Heap对象而有一个DLL使用静态连接的运行库它就拥有一个和其他DLL不同的Heap 对象当在其他DLL中分配的内存在这个DLL中释放时问题就出现了

关键词new/关键词delete

这两个词是C++内置的关键词(keyword)当C++编译器看到关键词new的时候例如

CMyObject*pObj=newCMyObject;

编译器会执行以下两个任务

在堆上动态分配必要的内存这个任务是由编译器提供的一个全局函数void* ::operator new(size_t)来完成的值得注意的是任何一个类都可以重载这个全局函数如果类重载了这个函数的化被类重载的那个会被调用

调用CMyClass的构造函数来初始化刚刚生成的对象当然如果分配的对象是C++中的基本数据类型则不会有构造函数调用

如果要深入全局函数void* ::operator new(size_t)的话我们会发现它的具体实现是通过调用malloc来分配内存的

有了这样的分析我们对这些动态内存分配方式有了一个更高一级的认识在我们的代码中就可以正确使用他们

上一篇:VC2005中System::String转换为std::string

下一篇:eater中实现“鼠标滑动行变色”的效果