Memory Management(内存管理)
GlobalMemoryStatus
此函数用于获得系统当前物理内存和虚拟内存的使用情况。
如果想要获得扩展虚拟地址空间,或者是您的程序运行在一台有超过4GB主内存的机器上,那么请使用GlobalMemoryStatusEx 函数来达到类似的要求。
函数声明如下:
VOID GlobalMemoryStatus(
LPMEMORYSTATUS lpBuffer //内存状态结构
);
参数表:
lpBuffer : 〔输出〕 一个指向 MEMORYSTATUS 结构的指针。函数将当前内存状况保存到该结构中。
返回值:
无返回值
说明:
您可以使用该函数来判断当前您可以在系统中分配到多少不会与其它程序相冲突的内存。
这个函数的返回是不确定的,无法保证连续两次调用该函数会得到相同的返回信息。
在一台内存超过4GB的机器上,GlobalMemoryStatus 函数会返回错误值。Windows2000或之后的版本会报告一个 -1 的值来表示数据溢出。之前的版本如windosNT则报告一个对真实内存取4GB模的一个值。由于以上的原因,我们使用GlobalMemoryStatusEx 取代该函数。
在一台拥有大于2GB而小于4GB内存的intel x86机器上GlobalMemoryStatus 函数总是在结构MEMORYSTATUS 成员dwTotalPhys 中返回2GB。同样的,如果总的可用内存在2 - 4GB之间,结构MEMORYSTATUS 的成员dwAvailPhys 最大可能值为2GB。如果可执行文件在连接时使用”/LARGEADDRESSWARE ”连接开关,那么函数GlobalMemoryStatus 会在以上两个成员中返回正确的值。
Virtual Address Space
(虚拟地址空间)
虚拟地址表示的是进程中非实际物理地址的位置。换句话说就是,系统为每个进程维护着一个页面映射,这个页面映射是一个内部的数据结构,它的作用是将虚拟地址转换为相应的物理地址。
虚拟地址空间分为以下几部分:
Windows NT 4.0 SP3 Server Enterprise Edition, Windows 2000 Advanced Server, and Windows .NET Enterprise Server:一般的,进程能够使用低端的3GB空间(0x00000000 到 0xBFFFFFFF)。高端的1GB内存(0xC0000000 到 0xFFFFFFFF)为系统保留部分。
Windows NT/2000/XP: 进程能够使用低端的2GB内存(0x00000000 到 0x7FFFFFFF),高端的2GB内存(0x80000000 到 0xFFFFFFFF)系统保留。
Windows 95/98/Me: 对应描述如下表
区间
|
用途
|
0K - ~64K (0xFFFF)
|
不可写。这块区域大约应是为系统装载一些MS-DOS的特性而保留的。这块内存对于进程而言是私有的。
|
~64K (0x10000) -
4 MB (0x3FFFFF) |
为兼容MS-DOS保留。这块内存对进程而言可读可写。然而,这段区域有可能保存着一些MS-DOS相关的结构或代码,所以进程不应该在这段区域随意读出或写入。这块内存对于进程而言是私有的。
|
4MB (0x400000) -
2GB (0x7FFFFFFF) |
用于代码和用户数据。用户数据可读可写。代码是只执行的。这块内存对进程而言是私有的。
|
2GB (0x80000000) -
3GB (0xBFFFFFFF) |
共享区。对于所有进程都可读写。一些系统的动态连接库和其它一些数据装载到这段区域。
|
3GB (0xC0000000) -
4GB (0xFFFFFFFF) |
系统内存。对任意进程都是可读可写。然而,需要注意的是,这段内存是保存低等级的系统代码的地方,所以,向这片区域写入数据可能会破坏系统可能造成灾难性后果。.
|
详情请参阅MSDN
下期预告:
Virtual Memory Functions
(
虚拟内存函数族)
Virtual Memory Functions(
虚拟内存函数族
)
此族函数用于进程操作或决定虚拟内存地址空间中页面的状态。他们可以实现以下一些操作:
1、
预留一个虚拟地址空间的区域。预留的地址空间不占用任何的实际物理内存,但是会防止其它分配操作在此范围内分配内存。它不会影响其它进程的虚拟地址空间。当进程需要把一个动态增长的数据结构分配在一个预留的内存空间中时,预留内存操作避免不必要的物理内存占用。进程在需要时能够为这块空间分配物理内存。
2、
将进程虚拟地址空间预留页的范围提交给进程,这样,这片物理存储区(不论是内存还是磁盘)只能被此进程访问。
3、
描述已提交页面区域的读/写、只读、拒绝访问等属性。不同于标准的分配函数的地方是它分配的页面总有 读/写 属性。
4、
释放已预留的内存区域。使这片虚拟内存区域对于调用进程后来的分配操作处于可用状态。
5、
把已提交页面区域解除提交。释放对应的物理存储区,使之对于后来的任意进程的分配操作有效。
6、
锁定一页或更多已提交页到物理内存中,使这些被锁定页面不回被系统交换到页面文件中。
7、
获得关于调用进程或指定进程虚拟地址空间某一区域之内已提交页面的资料。
8、
改变调用进程或指定进程虚拟地址空间指定区域已提交页面的访问限制级。
更多详细资料,请看下回分解
下期预告:
- Allocating Virtual Memory(分配虚拟内存)
- Freeing Virtual Memory(释放虚拟内存)
- Working With Pages (页面操作)
Allocating Virtual Memory
(分配虚拟内存)
虚拟内存函数用于操作内存页面。这些函数用当前机器上的页面的大小来实现描述内存的大小和地址的功能。
VirtualAlloc 函数执行以下的操作中的一个:
1、
预留一页或多页的自由页面。
2、
提交一页或多页预留页面。
3、
预留和提交一页或多页自由页面。
你可以指定你要预留或提交页面的起始地址,或者你也可以让系统来决定这个地址。函数将指定的地址调整到适当的页面边界。预留页面是不允许访问的,但已提交的页面可以被以页读/写、页只读、页访问禁止等访问规则进行分配。当页面被提交之后,在页面文件中就分配了存储区,但所有页面都只是在第一次试图读或写该页面的时候被调入物理内存。你可以用一般指针来访问用VirtualAlloc函数提交的内存。
Freeing Virtual Memory
(释放虚拟内存)
VirtualFree函数执行以下操作中的一个:
1、
取消提交一个或更多的已提交页面,把页面状态切换到预留。取消提交的页面将释放于该页面相关联的物理存储区,使这片区域能够被任意进程重新使用。所有被提交的页面块都可以被取消提交。
2、
释放一片包含一个或多个预留页面的内存块,把页面状态切换到空闲。已释放的页面块能够被该进程重新使用。被预留页面只能够一次释放全部的之前使用VirtualAlloc函数预留的块。
3、
同时取消提交和释放一个包含一个或多个页面的块,将这些页面的状态切换为空闲。指定的块必须包含全部之前使用VirtualAlloc函数预留的块,而且通常所有这些页面已经被提交。
当一个内存块被释放或者取消提交之后,你就不能再引用它。所有之前在其中的信息都永远消失。试图在一个空闲页面上执行读写操作会导致一个访问违例。如果你还需要这些某些信息,那么请不要取消提交或者释放包含这些资料的内存。
如果想要说明某片内存区域的数据不再游泳,那么在调用VirtualAlloc时使用MEM_RESET参数。这样这些页面上的数据将不会在读取或写入页面文件。然而,这块内存仍可再次被使用。
Working With Pages
(页面操作)
使用GetSystemInfo函数能够得到当前机器的页面大小。
VirtualQuery 和VirtualQuerayEx函数能够返回关于 某一进程的地址空间中始于指定地址的连续的页面空间 的资料。VirtualQuery返回关于调用进程的内存资料。VirtualQueryEx返回关于指定进程的内存资料而且通常能够支持需要处于调试态进程资料的调试器。页面区域会被限制在 向下调整到最近页面边界的指定地址上。一直延伸到所有拥有以下共同特性的后续页面:
1、
所有页面状态一致:是已提交或预留或空闲三状态之一。
2、
如果起始页面非空闲,那么所有该区域页面都是被VirtualAlloc一起初始化的内存页面组的一部分。
3、
所有页面访问控制级都一致:是 页只读、页读写、页禁止访问三级之一。
VirtualLock函数使进程能够锁定一页或多页已提交内存进入物理内存(RAM),防止系统将这些页面交换到页面文件中。它能够被用于确保在不进行磁盘访问的情况下使临界数据可访问。锁定页面进内存是危险的,这是因为它会限制系统管理内存的能力。的使用VirtualLock函数能够导致可执行代码被交换到页面文件从而降低系统性能。VirtualUnlock函数将被VirtualLock锁定的内存解锁。
VirtualProtect
函数能够调整所有在进程地址空间中的已提交页面的访问限制级。比如,进程可以分配读写页面来存储常变数据,并且之后它能够把访问控制级改变为只读或者禁止访问来防止以外的改写。
VirtualProtect
是一个用
VirtualAlloc
分配的页面上的典型的应用,但是,它也能够应用于使用其它分配函数分配的页面上。然而,
VirtualProtect
改变了全部页面的保护级,但是其它分配函数返回的指针并不一定要页面对齐。
VirtualProtectEx
函数类似于
VirtualProtect
函数,除了它只改变指定进程内存的限制级之外。改变限制级在调试器访问被调试进程的内存的时候会很有用处。
Memory Management Functions
(内存管理函数)
以下的函数用于内存管理
函数
|
描述
|
将一块内存从位置拷贝到另外一个位置
| |
将指定内存块内容填充为指定数据
| |
查找已经被写入虚拟内存区域的页面地址
| |
获得关于系统当前对于物理内存和虚拟的内存的使用信息。
| |
获得关于系统当前对于物理内存和虚拟的内存的使用信息。
| |
决定调用进程是否拥有对指定地址内存的读操作权。
| |
检验调用进程是否拥有对指定内存范围的读操作权。
| |
检验调用进程是否拥有对指定字符串所在地址区域的读操作权。
| |
检验调用进程是否拥有对指定内存范围的写操作权。
| |
将一块内存从一个位置移动到另外的位置。
| |
为某片虚拟内存区域重置写跟踪状态。
| |
用零值填充某片内存块。
|
以下是 AWE(Address Windowing Extensions) 函数
函数
|
描述
|
分配物理内存页面与进程的AWE区域建立或取消映射
| |
释放先前由AllocateUserPhysicalPages函数分配的物理内存页面。
| |
映射在AWE区域内的指定地址分配的物理内存。
| |
同上
|
以下的函数是全局(global)和本地(local)函数。这类函数运行速度较之其它内存管理函数为慢并且有很多特性没有提供。这就是说,新的应用程序应该尽量使用堆函数(heap functions).然而,全局函数(global functions)仍然被用在DDE和剪贴板操作中。
函数
|
描述
|
从堆中分配指定字节数量的内存。
| |
丢弃指定的全局内存块
| |
返回关于指定全局内存对象的信息
| |
释放指定的全局内存对象。
| |
返回指定全局内存块的指针的句柄。
| |
锁定一个全局内存对象并且返回指向该内存块第一个字节的指针。
| |
改变指定全局内存对象的大小和属性。
| |
得到指定内存对象的当前大小。
| |
减少对一个内存对象的锁定数量。
| |
从堆中分配指定数量的内存。
| |
丢弃指定的本地内存对象
| |
返回关于指定本地内存对象的信息。
| |
释放指定的本地内存对象。
| |
得到指向指定本地内存对象的指针的句柄。
| |
锁定本地内存对象并且返回指向该内存对象的第一个字节的指针。
| |
改变指定本地内存对象的大小或者属性。
| |
返回指定本地内存对象的当前大小。
| |
减少对某内存对象的锁定数量。
|
以下是堆函数族。
函数
|
描述
|
获得调用进程的堆的一个句柄。
| |
获得调用进程所有有效的堆的句柄。
| |
从堆中分配一块内存
| |
尝试压紧指定的堆。
| |
创建一个堆对象。
| |
销毁指定的堆对象。
| |
释放一块从堆中分配的内存。
| |
尝试获得与指定堆关联的锁定。
| |
获得关于指定堆的资料。
| |
从堆中重新分配一块内存。
| |
为指定的堆设置堆信息。
| |
获得一个在堆上的内存块的大小。
| |
获得与指定堆相关联的一个锁定的所有者。
| |
尝试使指定的堆有效。
| |
枚举指定堆上的内存块。
|
以下是虚拟内存函数。
函数
|
描述
|
保留或提交调用进程虚拟地址空间的某一区域的页面。
| |
保留或提交调用进程虚拟地址空间的某一区域的页面。
| |
释放或取消提交调用进程虚拟地址空间的某一区域的页面。
| |
释放或取消提交调用进程虚拟地址空间的某一区域的页面。
| |
锁定指定的进程虚拟地址空间的指定块到物理内存中。
| |
改变调用进程虚拟地址空间已提交页面区域的访问限制级。
| |
改变调用进程虚拟地址空间已提交页面区域的访问限制级。
| |
提供关于调用进程虚拟地址空间页面区域的资料。
| |
提供关于调用进程虚拟地址空间页面区域的资料。
| |
对某进程虚拟地址空间的某区域的页面解锁。
|