|
C 语言标准定义了一系列的内存管理函数,如 malloc(), memcpy(), free() 等。Windows 系统也支持标准 C 。在应用程序中,也可以使用标准 C 内存管理函数来对内存分配释放,操作管理。
ctrdll.dll (crt : c run time) 中包括了各种标准 C 库函数的实现,使用标准 C 库函数并不会脱离 Windows 系统内存管理模式。事实上,在 Windows 上,和大多数标准 C 库函数一样,像 malloc() 这种函数仍然是通过 API 函数实现的。malloc() 在对其参数进行了简单的处理后就直接调用了 HeapAlloc() 函数。
堆内存管理依赖于虚拟内存管理。在创建堆时,HeapCreate() 函数会向系统请求虚拟内存分页,然后在这个堆上的内存分配实际上是从虚拟内存管理中获取的内存分页上再分配大小任意的内存块。如果在建立堆时指定了堆的大小是固定的,那么在堆上分配内存块时,其范围不能超过设置的堆大小,堆大小一定是内存页大小的整数倍。如果在建立堆时不固定堆的大小,那堆管理函数会根据分配的请求数量,动态地向虚拟内存管理函数请求内存分页。
VirtualAlloc() 的功能是对进程虚拟地址空间中内存分页的状态进行管理,属于虚拟内存管理(以内存页为单位)的范围。当然,内存的分配也是通过改变虚拟内存内存页面属性来实现的,所以 VirtualAlloc() 间接达到了分配内存的目的。
堆管理器也是依赖于虚拟内存管理的,在收到 HeapAlloc() 的内存分配的请求时,对管理器会根据情况决定是否使用虚拟内存管理机制分配新的页面,以及如何在页面上分配内存块,因此从这个层次上来讲,VirtualAlloc() 更为底层。
实际上,只要虚拟内存管理函数将页面属性设置为 “已提交”后,就可以在上面进行读写等操作。堆管理函数为应用程序提供了一种更灵活,更简单的方式来管理这些“已提交”的内存,其好处一就是分配更简单,二是可以分配任意大小的内存,三是不用直接与复制的内存分页机制打交道。
如标准 C 中的 malloc() 函数实际上就是直接调用了 HeapAlloc() ,因此其效率也会比直接使用 HeapAlloc() 来得低。
因为 HeapAlloc() 和 VirtualAlloc() 的层次和功能定位都不同,因此在效率上没有可比性。从原理上来讲,HeapAlloc() 在分配内存时,如果堆管理器中有足够的已提交的页面可用,那么它就不需要将内存分页从其他状态(空闲或保留的)改为已提交状态,只需要在堆管理器中进行相关管理即可。如果在分配时没有足够的已提交页面可供使用,那么还需要将虚拟内存分页从其他状态改为已提交状态,在有足够的可使用已提交页面时,再由对管理器进行相关管理。
关于内存页的 3 个状态概念可参考:《虚拟地址空间内存页的 3 种状态》 |
|