当前位置:鱼C工作室 >Win32汇编 > 查看文章

内存管理2 – Win32汇编语言055

内存管理2

 

让编程改变世界

Change the world by program


 

标准内存管理函数

 

标准内存管理函数的功能是在进程的默认堆中申请和释放内存块,它由下面一些函数组成:

GlobalAlloc,GlobalFree 和 GlobalReAlloc 分别用来申请、释放和修改内存大小。

GlobalLock 和 GlobalUnlock 用来进行锁定操作。

GlobalDiscard,GlobalFlags,GlobalHandle 和 GlobalSize 等用来丢弃内存或获取已分配内存的一些信息。

 

友情提示:

在 Win16 中,内存管理函数有”全局”或”本地”之分,它们的区别在于返回的指针是远指针还是近指针,全局内存管理函数名是以”Global”开头的,而”本地”内存管理函数名是以”Local”开头的。

 

在 Win32 中,指针并没有远近之分,只有一种32位的指针,但为了保持向下兼容,这些函数名仍然沿用了下来。
这两组函数在 Win32 中是完全相同的,读者可以自由使用名字以 Global 或 Local 为前缀的函数。

 

用标准内存管理函数可以分配的内存有两种:

固定地址的内存块和可移动的内存块

可移动的内存块又可以进一步定义为可丢弃的,让我们逐步来讨论它们的不同。

 

固定的内存块

 

常规意义上的内存就是固定的内存块,因为申请到内存后,这块内存的线性地址是固定不变的。

要申请一块固定的内存,可以使用函数:

invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,dwBytes

 

解释一下:

第一个参数是标志,GMEM_FIXED 表示申请的是固定的内存块,GMEM_ZEROINIT 表示需要将内存块中的所有字节预先初始化为0,也可以简单地使用 GPTR 标志,它就相当于是GMEM_FIXED or GMEM_ZEROINIT。

 

第二个参数 dwBytes 指出了需要申请的是以字节为单位的内存大小。如果内存申请失败,eax 中返回 NULL,否则返回值是一个指向内存块起始地址的指针,用户需要保存这个指针,在使用内存或者释放内存的时候还要用到它。

 

如果要释放一个先前申请的固定内存块,可以使用 GlobalFree 函数:

invoke GlobalFree, lpMemory

 

如果释放成功,函数返回 NULL,否则函数返回的值就是输入的 lpMemory。

另外程序在不再使用内存块的时候应该使用这个函数将内存释放,不过就算程序在退出的时候忘记了释放内存,Windows 也会自动将它们释放。

在实际使用中往往需要改变一个内存块的大小,这时候就要用到 GlobalReAlloc 函数。

 

该函数可以缩小或扩大一块已经申请到的内存:

invoke GlobalReAlloc,lpMemory,dwBytes,uFlags
.if eax
    mov lpNewMemory,eax
.endif

 

lpMemory 是先前申请的内存块指针,dwBytes 是新的大小,如果这个数值比原来申请的时候要小。

也就是需要缩小内存块,那么 uFlags 标志参数可以是 NULL。

如果缩小内存块的操作不成功,那么函数的返回值为0,否则是新的缩小了的内存块指针,当然,这个指针和原来的指针肯定是一样的。

但是需要扩大一个内存块的时候,情况就稍微有些复杂了。

 

我们来考虑这样一种情况:

首先申请两个 1000h 大小的固定内存块,得到两个指针,可以发现第二块几乎紧接第一块内存的。(请自行尝试)

一般情况下如果第一块内存的地址是 X,那么第二块内存的地址几乎就是 X + 1000h,如果需要将第一个内存块扩大到 2000h 字节,那么只能在别的地方开辟一个 2000h 大小的内存块,因为原来位置后面的 1000h 已经被第二块内存占用了,这就意味着新的指针可能和原来的不一样。

 

可以在 GlobalReAlloc 函数中通过指定不同的 uFlags 来规定是否允许 Windows 在必要的时候移动内存块。

当 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,然后程序判断返回值。

如果改变大小成功的话,则用新的指针替换原来的指针,其他和原来指针有关的值也不要忘了同时更新。

接下来,我们来讨论:可移动的内存块

 

分页阅读: 1 2 下一页
为您推荐

报歉!评论已关闭.