13、Windows API 内存管理(3)

二、堆管理

    用户使用内存分配函数分配的内存都位于堆中,所以使用堆管理函数对内存进行分配、释放等是最为直接的方式。

    Windows系统中,每个进程都有自己的堆,每个进程的堆的数量也有所不同。Windows系统中所谓的“堆”(Heap)并不是内存块,而是一种用于内存管理的对象,也是一种内存组织的形式。进程可以从属于自己的堆上分配内存和释放内存。堆包括有若干种属性,如堆的大小最大值可以是固定的、也可以是“可增长的”;堆上的数据内容是否可以作为代码可执行;堆是否可连接存取等。

三、全局和局部内存管理

    32位Windows系统中并没有区分全局堆和局部堆,Windows系统中之所以还存在着全局和局部函数的概念是为了和16位系统相兼容。GlobalAlloc、LocalAlloc函数所分配的内存没有什么区别,内存分配的效果与HeapAlloc函数类似。但是GlobalAlloc与LocalAlloc分配内存时比HeapAlloc要慢。

    因此更推荐使用Heap函数。

四、虚拟内存管理

    内存管理的原理都由系统的内存管理器实现,应用程序只能管理属性于自己的虚拟地址空间。

    进程的虚拟地址空间内存页面存在3种状态,分别为空闲的(free)、保留的(reserved)和提交的(Committed)。

wps_clip_image-31189

五、内存分配的比较

使用VirtualAlloc,VirtualFree等函数进行操作,其操作的基本单位是内存页面。

HeapAlloc、GlobalAlloc、LoaclAlloc在功能上没有大的区别,都是在堆中分配内存,分配的内存不需要进行页对齐,也不用关心分页机制、页面状态、页面属性等内容。HeapAlloc是程序在需要分配内存时最直接的方式。这些内容由堆管理器负责。

堆内存管理依赖于虚拟内存管理。在创建堆时,HeapCreate API函数会向系统请求虚拟内存分页,之后在这个堆上的内存分配实际上是在从虚拟内存管理中获取的内存分页上再分配大小任意的内存块,如果在建立堆时指定了固定了堆大小,那么在堆上分配内存块时,其范围不能超过设置的堆大小,堆大小一定是内存页大小的整数倍。如果在建立堆时不固定堆的大小,堆管理函数会根据分配的请求数量,动态地向虚拟内容管理函数请求内存分页。

VirtualAlloc的功能是对进程虚拟地址空间中内存分页的状态进行管理,属于虚拟内存管理(以内存页面为单位)的范围。当然内存的分配也是通过改变虚拟内存页面属性来实现的,所以VirtualAlloc间接达到了分配内存的目的。堆管理器也是依赖于虚拟内存管理的,在收到HeapAlloc的内存分配的请求时,堆管理器会根据情况决定是否使用虚拟内存管理机制分配新的页面,以及如何在页面上布局分配的内存块,从这个层次上讲VirtualAlloc更为底层

    实际上只要虚拟内存管理函数将页面属性设置为“已提交”后,就可以在之上进行读写等操作。

    堆管理函数为应用程序提供了一种更灵活、更简单的方式来管理这些“已提交”的内存。其好处一是分配更简单,二是可以分配任意大小的内存,三是不用直接与复制的内存分页机制打交道。

    标准C函数的内存分配函数则直接使用了HeapAlloc。

    HeapAlloc、GlobalAlloc、LoaclAlloc在32位系统上功能上是一致的,但是由于Globa]_Alloc、LoaclAlloc需要兼容16位系统,所需进行的判断和处理会更多,因此GlobalAlloc、LoaclAlloc较HeapAlloc效率低。当然标准C函数malloc也是调用HeapAlloc实现的,所以其效率也必然比HeapAlloc低。

    由于HeapAlloc与VirtualAlloc功能定位上的不同,所以在效率上没有可比性。从原理上讲,HeapAlloc在分配内存时,如果堆管理器中有足够的已提交的页面可以使用,那么它不需要将内存分页从其他状态改变为已提交状态,只需要在堆管理器中进行相关管理;如果在分配时没有足够的已提交页面供使用,那么还需要将虚拟内存分页从其他状态改变为已提交状态,在有足够的可使用的已提交页面的情况下,再由堆管理器进行相关管理。

原文地址:https://www.cnblogs.com/mydomain/p/1930571.html