按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
invoke HeapLock,hHeap
invoke HeapUnlock,hHeap
如果函数执行成功,返回值为非0值,否则函数返回0。一般来说,很少在程序中使用这两个函数,而总是使用HEAP_NO_SERIALIZE标志来进行同步控制,指定了这个标志的话,HeapAlloc,HeapReAlloc,HeapSize和HeapFree等函数会在内部自己调用HeapLock和HeapUnlock函数。
Heappact函数用于合并堆中的空闲内存块并释放不在使用中的内存页面:
invoke Heappact,hHeap,dwFlags
HeapSize函数返回堆中某个内存块的大小,这个大小就是使用HeapAlloc以及HeapReAlloc时指定的大小:
invoke HeapSize,hHeap,dwFlags,lpMemory
lpMemory指定了需要返回大小的内存块,函数的返回值是内存块的大小,如果执行失败,函数返回?1。
10。1。5 虚拟内存管理函数
不管某个进程实际可用的物理内存是多少,每个进程可以使用的地址空间总是2 GB,用户程序不必考虑一个线程地址对应的物理内存究竟安排在什么地方——是在真正的物理内存中?在磁盘交换文件中?还是根本没有物理内存与之对应。
一个进程的整个地址空间是客观存在的,但是否有内存与该段地址空间中的地址相关联是另外的问题,Windows负责在适当的时间把线程地址映射到物理内存或磁盘上的交换文件上,这就是虚拟内存的基本概念。
在程序运行的时候,进程中每个地址都可以处于下列3种状态的1种中:
● 占用状态——线程地址已经映射到实际的物理内存中。也称为已提交状态。
● 自由状态——没有映射到物理内存中,线程地址当前也没有被程序使用。
● 保留状态——虽然线程地址没有映射到物理内存中,但它不会被使用,直到程序希望使用它为止。
进程开始的时候,所有地址都是处于自由状态的,这意味着它们都是自由空间并且可以被提交到物理内存,或者为将来使用而保留起来。任何自由状态地址在能够被使用前,必须首先被分配为保留状态或已提交状态。
当使用标准内存管理函数分配内存的时候,用户无法指定内存块位于哪个线程地址,或者不要位于哪个线程地址,而使用虚拟内存管理函数可以做到这一点。但这样做的理由是什么呢?考虑这样一种情况:程序需要一个内存块用做缓冲区,随着程序的运行,这个内存块可能随时需要扩展,最大可能扩展为100 MB大小,所以希望系统在分配其他内存块的时候不要使用这个内存块后面100 MB大小范围内的地址空间,这样,就可以随时将内存块扩大而不必移动它的位置。
除了这样一个主要的用途外,虚拟内存管理函数还提供转换虚拟地址空间页状态的能力,一个应用程序可以把内存的状态从已提交改变为保留,或把保护的模式从 PAGE _READWRITE (可读写)改变为 PAGE_READONLY(只读),从而防止对某段地址空间的写访问;应用程序也可以锁定一页内存,不让它被交换到磁盘中。
虚拟内存管理函数是一组名字以Virtual开头的函数,主要包括下面几种:
● VirtualAlloc和VirtualFree——进行地址空间的分配和释放工作。
● VirtualLock和VirtualUnlock——对内存页进行锁定和解锁。
● VirtualQuery或VirtualQueryEx——查询内存页的状态。
● VirtualProtect或VirtualProtectEx——改变内存页的保护属性。
1。 保留和释放地址空间
保留或提交一段地址空间,使用VirtualAlloc函数,释放或解除提交地址空间,则使用VirtualFree函数。先来看Virtualalloc函数的使用方法:
invoke VirtualAlloc,lpAddress,dwSize,flAllocationType,flProtect
lpAddress参数指定需要保留或提交的地址空间的位置,参数可以使用NULL值也可以指定一个具体的地址。NULL值表示由函数自行在某个最方便的位置保留地址范围,非NULL值指定了一个准确的初始地址。如果函数返回NULL,表示执行失败,否则返回一个指针,指向被保留地址范围的开始位置。
dwSize参数表示函数应该分配的地址范围大小,它可以是0 B~2 GB的任意值,但系统会自动把它进位到一个页面的整数倍大小。另外,虽然参数的最大值可以指定为2 GB,但实际上能够被保留的最大值是该进程中最大的连续自由地址空间。
flAllocationType参数用来决定如何分配地址,它可以是以下取值的组合:
● MEM_MIT——为指定地址空间提交物理内存。
● MEM_RESERVE——保留指定地址空间,不分配物理内存。
● MEM_TOP_DOWN——尽可能使用高端的地址空间。
flProtect参数用来指定保护的类型,它可以是以下取值之一:
● PAGE_READONLY——为已提交物理内存的地址空间设定只读属性。
● PAGE_READWRITE——为已提交物理内存的地址空间设定可读写属性。
● PAGE_EXECUTE——为已提交物理内存的地址空间设定可执行属性。
● PAGE_EXECUTE_READ——为已提交物理内存的地址空间设定可读和可执行属性。
● PAGE_EXECUTE_READWRITE——为已提交物理内存的地址空间设定可读、可写和可执行属性。
● PAGE_NOACCESS——将保留的地址空间设定为不可存取模式。
VirtualFree函数的使用语法是:
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第10章 内存管理和文件操作
10。1 内 存 管 理(7)
invoke VirtualFree,lpAddress,dwSize,dwFreeType
lpAddress和dwSize参数指定地址和地址空间的大小,dwFreeType指定释放地址空间的方式,它可以是以下的数值:
● MEM_DEMIT——为一个已经提交物理内存的地址空间解除提交。
● MEM_RELEASE——释放保留的地址空间。
现在来看如何使用它们来保留地址空间和释放保留的地址空间。使用VirtualAlloc函数保留一个地址空间的分配方式使用MEM_RESERVE,由于被保留的地址空间还没有提交给物理内存,是无法访问的,所以保护属性必须使用PAGE_NOACCESS标志,具体的语句是:
invoke VirtualAlloc,NULL,10485760,MEM_RESERVE,PAGE_NOACCESS
。if eax
mov lpAddress,eax
。endif
这一段代码导致系统保留一个10 MB大小的地址空间。当在一个进程中保留地址时,没有物理内存页被提交,也没有在页文件中为它保留空间,而只是阻止了其他内存分配函数对该段地址的请求而已,保留一个地址范围并不保证将来会有可用的物理内存来提交给这些地址。
保留地址的操作是很快的,保留一个小的地址范围和保留一个大范围的地址空间的速度差不多,因为在操作期间,并没有资源分配。
如果要释放保留的地址空间,可以使用MEM_RELEASE方式调用VirtualFree函数:
invoke VirtualFree,lpAddress,0,MEM_RELEASE
lpAddress就是上面调用VirtualAlloc返回的指针,dwSize参数在这里必须为0。当使用上面的VirtualAlloc函数保留了一段地址空间以后,接下来还可以继续多次调用同样的函数提交这段地址空间中的不同页面,所以到最后不同的页面可能处在不同的状态中(提交的和没有提交的)。如果用VirtualFree函数释放这个地址空间,所有的页面必须处在相同的状态下(可以是全部提交的或全部没有提交的),否则释放操作会失败。当不同页面的状态不同的时候,最好首先将所有的已提交页面逐一解除提交,最后再使用上面举例的方法释放整个地址空间。
有时候,两次调用VirtualAlloc函数保留了两段连在一起的地址空间,对于这种情况,虽然两段地址空间实际上是连在一起的,但也无法调用VirtualFree函数将它们一次释放,必须调用两次VirtualFree函数将它们分别释放。
2。 使用保留的地址空间
要使用保留的地址,首先必须提交物理内存给该地址。提交内存到地址与保留内存同样使用VirtualAlloc函数,只是调用的方式使用MEM_MIT标志。在已经保留的地址段中,内存可以按一页的大小被分次提交,也可以一次提交所有的保留地址。
当内存被提交时,可能全部被分配为物理内存页,也可能一部分或全部被分配在页文件中,直到它被访问。一旦内存页已提交,系统就会像对待用其他函数分配的内存块一样来对待它们。
使用VirtualAlloc函数提交地址空间的方法是:
invoke VirtualAlloc,lpAddress,4096,MEM_MIT,PAGE_READWRITE
。if eax
mov lpMemory,eax
。endif
这个语句将一个页面4 096 B的保留地址提交到物理内存。在提交的时候,lpAddress参数不能指定为NULL,而是要指定一个特定的地址来准确地指示被保留地址的哪一页会被提交。而且,页的属性现在要指定是可以访问的,不能再使用PAGE_NOACCESS,可以使用PAGE_READWRITE和PAGE_READONLY等属性。如果函数执行成功,返回的是被提交地址中第一页的起始线程地址,执行失败将返回NULL。
提交内存的时候,系统只能按页面的整数倍大小提交,函数会自动按照lpAddress和dwSize指定的范围把与这个范围同属一个页面的地址全部提交,所以当lpAddress指定的数值不是一个页的整数倍的时候,返回的lpMemory就不会和指定的lpAddress相同,而是被�