让编程改变世界
Change the world by program
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 函数。 该函数可以缩小或扩大一块已经申请到的内存: [codesyntax lang="asm"]invoke GlobalReAlloc,lpMemory,dwBytes,uFlags .if eax mov lpNewMemory,eax .endif[/codesyntax] lpMemory 是先前申请的内存块指针,dwBytes 是新的大小,如果这个数值比原来申请的时候要小。 也就是需要缩小内存块,那么 uFlags 标志参数可以是 NULL。 如果缩小内存块的操作不成功,那么函数的返回值为0,否则是新的缩小了的内存块指针,当然,这个指针和原来的指针肯定是一样的。 但是需要扩大一个内存块的时候,情况就稍微有些复杂了。
invoke GlobalReAlloc, lpMemory, dwBytes, GMEM_ZEROINIT or GMEM_MOVEABLE .if eax mov lpMemory,eax .endif[/codesyntax] 指定 GMEM_ZEROINIT 选项可以使内存块扩大的部分自动被初始化为0,然后程序判断返回值。 如果改变大小成功的话,则用新的指针替换原来的指针,其他和原来指针有关的值也不要忘了同时更新。 接下来,我们来讨论:可移动的内存块
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, dwBytes .if eax mov hMemory, eax .endif[/codesyntax] GMEM_MOVEABLE 标志指定了分配的内存是可移动的,GMEM_ZEROINIT 同样表示将申请到的内存块的内容初始化为0(也可以用 GHND 标志,它就相当于 GMEM _MOVEABLE or GMEM_ZEROINIT)。 如果内存申请失败,eax 中返回 NULL,成功的话返回值是一个句柄而不是内存指针,用户需要保存这个句柄,在锁定或释放内存的时候还要用到它。 一个进程可以申请的可移动内存的块数最大不能超过 65536 个,申请固定内存块时则没有数量限制。 要使用可移动内存之前,需要把它锁定,这相当于告诉 Windows 现在程序要使用这块内存了,不能将它移动,锁定内存使用 GlobalLock 函数: [codesyntax lang="asm"]
invoke GlobalLock, hMemory .if eax mov lpMemory, eax .endif[/codesyntax] 函数的入口参数是 GlobalAlloc 返回的内存句柄,如果锁定成功,函数返回一个指针,如果锁定失败,则函数返回NULL。 当程序暂时不需要操作这块内存的时候,应该将它解锁,否则和使用固定的内存块就没有区别了,解锁使用 GlobalUnlock 函数:
invoke GlobalUnlock, hMemory
函数的参数同样是 GlobalAlloc 返回的句柄,解锁成功的话函数返回非0值。 有个问题:在多线程的程序中,两个地方同时锁定内存,但当一个地方还在使用的情况下另一个地方却调用 GlobalUnlock 将内存解锁了怎么办? 其实不用担心这个问题,Windows 为每个可移动的内存句柄维护一个锁定计数,每次锁定内存的时候计数加 1,解锁的时候计数减 1,只有当计数为 0 的时候内存才真正被解锁。 所以只要程序中的 GlobalLock 函数和 GlobalUnlock 函数是配对的,就不用担心这个问题。 要释放一个可移动的内存块,同样使用GlobalFree 函数:invoke GlobalFree, hMemory
但使用的参数是 GlobalAlloc 返回的内存句柄,如果释放成功,函数返回 NULL。不管内存当前是否处在锁定状态,都可以被成功释放。 调整可移动内存块的大小,同样使用 GlobalReAlloc 函数:invoke GlobalReAlloc, hMemory, dwBytes, GMEM_ZEROINIT or GMEM_MOVEABLE
如果调整成功,返回值就是输入的 hMemory,失败的话返回值是 NULL。即使内存块在锁定状态,函数仍然可以调用成功。 但这时候内存块可能已经被移动了位置,原来用 GlobalLock 函数获取的指针可能已经失效了。 所以调整可移动内存块的大小最好还是先将内存解锁,等调整完毕以后再锁定使用。 由于使用可移动的内存块多了一个锁定的动作,速度自然要比使用固定的内存块要慢一点,但固定内存块又存在碎片问题,程序中使用哪种方法有个取舍的问题。 如果程序要频繁地分配和释放不定长的内存块,内存的碎片化现象就比较严重,特别是当程序长时间运行时,这种情况下使用可移动内存块比较好。 如果程序只进行少量的内存操作,或者虽然频繁分配和释放内存,但使用的内存块长度都是一样的,则使用固定内存块可以节省时间。 [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://kuai.xunlei.com/d/BdsUAwrRHwBnT7JS58b']视频下载[/Downlink]