内存管理相关的几个函数

作者在 2014-02-09 11:23:35 发布以下内容

一、内存管理基础

win32中的内存管理是分层次的,系统提供了几组层次不同的函数来管理内存,它们是
标准内存管理函数、堆管理函数、虚拟内存管理函数和内存映射文件函数。
windows充分利用了80X86处理器保护模式下的线性寻址机制和分页机制,这些机制是
win32内存管理的基础。
1)虚拟内存管理函数:管理虚拟内存,主要用于保留/提交/释放虚拟内存,在虚拟内存
页上改变保护方式、锁定虚拟内存页,以及查询一个进程的虚拟内存等操作,这是一组位于
底层的函数。
2)堆管理函数:堆的主要功能是有效地管理内存和进程的地址空间。win32中,进程可以
使用的整个地址空间就是一个堆。并且堆的概念又被引申了一步:win32中分两种堆,一种
是进程的默认堆,默认堆只有一个,指的就是可以使用的整个地址空间;另一种是动态堆,
也称私有堆,一个进程可以随意建立多个私有堆,也可以将它们释放,私有堆全部位于默认堆中。
3)标准内存管理函数:总是在默认堆中分配和释放内存,这组函数就是常规意义上的内存管理函数。
4)内存映射文件函数:相对比较独立,它是为了文件操作的方便性而设立的。可以将一个文件直接映射
到进程的地址空间中,这样可以通过内存指针用读写内存的方法直接存取文件内容。

(一)标准内存管理函数:
GlobalAlloc          申请
GlobalFree           释放
GlobalReAlloc        修改
GlobalLock           锁定
GlobalUnlock
GlobalDiscard
GlobalFlags
GlobalHandle
GlobalSize

用标准内存管理函数可以分配的内存有两种:固定地址的内存块和可移动的内存块,而可移动
的内存块又可以进一步定义为可丢弃的。

1)固定内存块:
申请:
invoke GlobalAlloc, GMEM_FIXED or GMEM_ZEROINIT, dwBytes
.if eax
mov lpMemory, eax
.endif

GMEM_FIXED or GMEM_ZEROINIT 也可用标志GPTR代替

释放:
invoke GlobalFree, lpMemory
成功返回0。另,程序在退出时如果忘了释放,windows也会自动释放。

改变大小:
invoke GlobalReAlloc, lpMemory, dwBytes, uFlags
.if eax
mov lpNewMemory, eax
.endif
lpMemory是先前分配的指针,dwBytes是新的大小。
如果新的大小比原来小:那么uFlags设置为NULL就可以了,成功的话,返回的指针跟原来应该是一样的。
不成功的话返回0。
如果新的大小,比原来的要大,这时候情况就要复杂得多了。
因为原来这块内存的后面有可能也是被分配了的。
这时可以在uFlags中指定 GMEM_MOVEABLE 来表示,如果需要移动内存块 ,windows 会在别的地方
开辟一块新的内存,并把原来内存块中的内容自动复制,这个时候返回的指针是新的指针,原来的指针
作废。如果不指定 GMEM_MOVEABLE 那么只有在内存块后面扩展所需的空间没有被使用时,函数
才会执行成功,否则,函数失败并返回NULL。
为了保证内存块扩大成功,建议用下面的语句:
invoke GlobalReAlloc, lpMemory, dwBytes, GMEM_ZEROINIT or GMEM_MOVEABLE
.if eax
mov lpMemory, eax
.endif
指定 GMEM_ZEROINIT 表示扩大部分被初始化为0。

2)、可移动的内存块
为了防止内存碎片
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, dwBytes
.if eax
mov hMemory, eax
.endif
GMEM_MOVEABLE or GMEM_ZEROINIT 标志可以用 GHND 代替。
函数失败返回0,成功的话返回的是句柄而不是内存指针(因为地址是可能要移动的)。用户要保存这个句柄
在锁定或释放内存的时候还要用到它。
注意:一个进程可以申请的可移动内存的块数量不能超过65 536个,申请固定内存块的时候则没有数量限制。
要使用可移动内存块之前,要先把它锁定,这相当于告诉windows现在程序要使用这个内存块了,不能将它移动:
invoke GlobalLock, hMemory
.if eax
mov lpMemory, eax
.endif
锁定成功,则返回一个指针,就相当于固定内存块返回的地址指针。失败返回0。
当程序暂时不需要操作这个内存块时,应该将他解锁:
invoke GlobalUnlovk, hMemory
失败返回0,成功返回非0。
可能有这样的疑问:在多线程中,两个地方同时锁定内存,但当一个地方还在使用的情况下另一个地方调用了解锁怎么办?
实际上在windows中为每个可移动的内存句柄维护了一个锁定计数,每次锁定的时候计数加1,解锁的时候减1,只有为0的时候
才真正被解锁。所以,只要程序中的锁定和解锁是配对的,就不用担心这个问题。
要释放一个可移动内存块,同样使用:
invoke GlobalFree, hMemory
成功返回NULL,不管内存是否在锁定状态都可以释放。
调整大小,同样
invoke GlobalReAlloc, hMemory, dwBytes, GMEM_ZEROINIT or GMEM_MOVEABLE
成功,返回值就是输入的hMemory,失败返回0

原文:http://hi.baidu.com/zhaxiu3/item/22934f146489ff088fbde4f6

默认分类 | 阅读 2514 次
文章评论,共0条
游客请输入验证码