友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
飞读中文网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

windows环境下32位汇编语言程序设计-第92章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!



申请内存的请求只有一个能马上执行,其他将处于等待状态,对于一个私有堆来说,这个限制仍然存在,当从堆中分配内存时,系统有下面的操作步骤:

(1)遍历已分配的和空闲的内存块的链接表。

(2)寻找一个空闲内存块的地址。

(3)通过将空闲内存块标记为“已分配”来分配新内存块。

(4)将新内存块添加给内存块链接表。

当两个线程几乎同时在同一个堆中申请内存时,如果第一个线程执行了(1)、(2)两步的时候被系统切换到第二个线性,线程2同样又执行(1)、(2)两步,那么它们找到的空闲内存块就会是同一块内存,结果可想而知。解决问题的办法就是让单个线程独占对堆和它的链接表的访问权,当一个线程全部执行了这4个步骤后才允许第二个线程开始第一个步骤。

在用默认参数建立的堆中申请内存,系统会进行独占的检测工作,当然这要花费一定的系统开销。但是当以下情况存在时,可以保证不会同时有多个线程在同一个堆中申请内存:

●   进程只使用一个线程。

●   进程使用多个线程,但是每个线程只访问属于自己的私有堆。

●   进程使用多个线程,但程序中已经有其他措施来保证它们不会同时去访问同一个私有堆。

在这些情况下,可以指定HEAP_NO_SERIALIZE    标志来建立私有堆,这样建立的堆不会进行独占性的检测,访问速度可以更快。

参数dwInitialSize指定创建堆时分配给堆的物理内存,随着堆中内存的分配,当这些内存被使用完时,堆的长度可以自动扩展。dwMaximumSize参数指定了能够扩展到的最大值,当扩展到最大值时再尝试在堆中分配内存的话就会失败,这个值决定了系统给堆保留的连续地址空间的大小,函数会自动将这两个参数的数值调整为页面大小的整数倍。如果dwMaximumSize参数的值指定为0,那么堆没有最大值限制,扩展范围只受限于空闲的内存总量。如果dwMaximumSize指定为非0值,在堆中申请的最大单个内存块不能大于7FFF8h(相当于524 KB),dwMaximumSize指定0的话就没有这个限制。

如果一个私有堆不再需要了,可以通过调用HeapDestroy函数将它释放:

    invoke  HeapDestroy,hHeap

释放私有堆可以释放堆中包含的所有内存块,也可以将堆占用的物理内存和保留的地址空间全部返还给系统。如果函数运行成功,返回值是TRUE。当在进程终止的时候没有调用HeapDestroy函数将私有堆释放时,系统会自动释放。

虽然在默认堆中的内存申请主要使用标准内存管理函数,而堆管理函数的主要管理对象是私有堆,但是如果编程者愿意的话,也可以用堆管理函数在默认堆中分配内存,毕竟默认堆也是一个堆,但这样的话首先需要有一个句柄来代表默认堆,默认堆的句柄不能用HeapCreate来创建,但可以用GetProcessHeap函数来获取,这个函数没有输入参数,如果执行成功则返回默认堆的句柄。注意:这个句柄是“获取”的而不是“创建”的,所以不能调用HeapDestroy来释放它,如果对它调用HeapDestroy函数,系统会将它忽略。

2。 在堆中分配和释放内存块

如果要在堆中分配内存块,可以使用HeapAlloc函数:

    invoke  HeapAlloc,hHeap,dwFlags,dwBytes

    。if     eax && (eax 《 0c0000000h)

            mov     lpMemory,eax

    。endif

hHeap参数就是前面创建堆时返回的堆句柄(或者使用GetProcessHeap函数得到的默认堆句柄),用来表示在哪个堆中分配内存,dwBytes是需要分配的内存块的字节数,dwFlags是标志,它可以是下面值的组合:

●   HEAP_NO_SERIALIZE——当使用HeapCreate时指定了HEAP_NO_SERIALIZE标志,以后这个堆中使用的所有HeapAlloc函数都不进行独占检测。如果使用HeapCreate时没有指定HEAP_NO_SERIALIZE标志,可以在这里使用HEAP_NO_SERIALIZE标志单独指定对本次分配操作不进行独占检测。

●   HEAP_GENERATE _EXCEPTIONS——如果申请内存失败函数返回具体的出错原因,而不仅返回一个NULL。同样,当使用HeapCreate时指定了此标志的情况下,在这里就不必再一次指定。

●   HEAP_ZERO_MEMORY——将分配的内存用0初始化。

当函数分配内存成功的时候,返回值是指向内存块第一个字节的指针,如果分配内存失败,返回值要视dwFlags的设置,如果没有指定HEAP_GENERATE_EXCEPTIONS标志,那么返回值为NULL,否则,返回值可能是下面的数值:

●   STATUS_NO_MEMORY——取值为0C0000017h,表示内存不够。

●   STATUS_ACCESS_VIOLATION——取值为0C0000005h,表示参数不正确或者堆被破坏。

在堆中分配的内存块只能是固定地址的内存块,不像GlobalAlloc函数一样可以分配可移动的内存块。如果要释放分配到的内存块,可以使用HeapFree函数:

    invoke  HeapFree,hHeap,dwFlags,lpMemory

hHeap参数是堆句柄,lpMemory是HeapAlloc函数返回的内存块指针,dwFlags参数中也可以使用HEAP_NO_SERIALIZE标志,含义与使用HeapAlloc时相同。当函数执行成功的时候,返回值为非0值,执行失败则函数返回0。

对于用HeapAlloc分配的内存块,也可以使用HeapReAlloc重新调整大小:

invoke  HeapReAlloc,hHeap,dwFlags,lpMemory,dwBytes

    。if     eax && (eax 《 0c0000000h)

            mov     lpMemory,eax

    。endif



 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第10章 内存管理和文件操作


10。1 内 存 管 理(6)

    
其中dwBytes指定了新的大小,dwFlags为标志,可以组合指定的标志有:

●   HEAP_GENERATE_EXCEPTIONS——参见HeapAlloc函数的说明。

●   HEAP_NO_SERIALIZE——参见HeapAlloc函数的说明。

●   HEAP_ZERO_MEMORY——当扩大内存块的时候,将新增的部分初始化为0,当缩小内存的时候,本参数无效。

●   HEAP_REALLOC_IN_PLACE_ONLY——与GlobalReAlloc函数类似,当内存块的高处已经被其他内存块占据的时候,要扩大内存块必须将它移动位置,当没有指定这个标志的时候,函数会在需要的时候自动移动内存块,如果指定了这个标志,则不允许内存块移动,这时,当内存块高处不是空闲的时候,函数的执行会失败。

如果函数执行成功,返回值是指向新内存块的指针,显而易见,当缩小或扩大内存块时指定了HEAP_REALLOC_IN_PLACE_ONLY标志,则这个指针必定和原来的相同,否则的话,它既有可能和原来的指针相同也有可能不同。

3。 其他堆管理函数

除了上面的一些函数,堆管理函数中还有HeapLock,HeapUnlock,GetProcessHeaps,Heappact,HeapSize,HeapValidate和HeapWalk等函数。

GetProcessHeaps函数用来列出进程中所有的堆(注意:不要和用来获取默认堆句柄的GetProcessHeap函数搞混),HeapWalk用来列出一个堆中所有的内存块,HeapValidate函数用来检验一个堆中所有内存块的有效性。这3个函数平时很少使用,一般在调试的时候使用。

GetProcessHeaps函数的用法是:

    invoke  GetProcessHeaps,NumberOfHeaps,lpHeaps

其中lpHeaps是一个指针,指向用来接收堆句柄的缓冲区,NumberOfHeaps参数指定了这个缓冲区中可以存放句柄的数量,显然,缓冲区的长度应该等于NumberOfHeaps乘以4字节。函数执行后,进程中所有堆的句柄全部返回到缓冲区中,其中也包括默认堆的句柄。

HeapWalk函数的用法是:

    。repeat

            invoke  HeapWalk,hHeap,lpEntry

            push        eax

            ;检测缓冲区中的内存块信息

            pop eax

。until  !eax

hHeap是需要操作的堆句柄,lpEntry指向一个包含有PROCESS_HEAP_ENTRY结构的缓冲区。调用HeapWalk函数时,函数每次在PROCESS_HEAP_ENTRY结构中返回一个内存块的信息,如果还有其他内存块,函数返回TRUE,程序可以一直循环调用HeapWalk函数直到函数返回FALSE为止。在多线程的程序中使用HeapWalk,必须首先使用HeapLock函数将堆锁定,否则调用会失败。

HeapValidate用来验证堆的完整性或堆中某个内存块的完整性:

    invoke  HeapValidate,hHeap,dwFlags,lpMemory

其中hHeap指定要验证的堆。如果lpMemory为NULL,那么函数顺序验证堆中所有的内存块;如果lpMemory指定了一个内存块,则只验证这个内存块。dwFlags是标志,可以指定HEAP_NO_SERIALIZE 标志。如果验证结果是所有的内存块都完好无损,函数返回非0值,否则函数返回0。

HeapLock函数和HeapUnlock函数用来锁定堆和解锁堆。这两个函数主要用于线程的同步,当在一个线程中调用HeapLock函数时,这个线程暂时成为这个堆的所有者,也就是说只有这个线程能对堆进行操作(包括分配内存、释放、调用HeapWalk等函数),在别的线程中对这个堆的操作会等待在那里,直到所有者线程调用HeapUnlock解锁为止。这两个函数的语法如下:

    invoke  HeapLock,hHeap

    invoke  HeapUnlock,hHeap

如果函数执行成功,返回值为非0值,否则函数返回0。一般来说,很少在程序中使用这两个函数,�
返回目录 上一页 下一页 回到顶部 赞(0) 踩(1)
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!