Windows内存管理及C++语言内存分配

上传人:微*** 文档编号:168607665 上传时间:2022-11-11 格式:DOCX 页数:87 大小:149.80KB
收藏 版权申诉 举报 下载
Windows内存管理及C++语言内存分配_第1页
第1页 / 共87页
Windows内存管理及C++语言内存分配_第2页
第2页 / 共87页
Windows内存管理及C++语言内存分配_第3页
第3页 / 共87页
资源描述:

《Windows内存管理及C++语言内存分配》由会员分享,可在线阅读,更多相关《Windows内存管理及C++语言内存分配(87页珍藏版)》请在装配图网上搜索。

1、Windows内存管理及C+语言内存分配本文背景:在编程中,很多Windows或C+的内存函数不知道有什么区别,更别谈有效使用; 根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结 描述,结合实例来阐明这个机制。本文目的:对Windows内存管理机制了解清楚,有效的利用C+内存函数管理和使用内存。本文内容:本文一共有六节,由于篇幅较多,故按节发表。其他章节请看本人博客的Windows 内存管理及C+内存分配实例(二)(三)(四)(五)和(六)。1 .进程地址空间1.1 地址空间 32164位的系统ICPU操作系统运行在硬件CPU上,32位操作系统运行于32位CPU上,6

2、4位 操作系统运行于64位CPU上;目前没有真正的64位CPU。32位CPU一次只能操作32位二进制数;位数多CPU设计越复杂,软件设计 越简单。软件的进程运行于32位系统上,其寻址位也是32位,能表示的空间是 232=4G,范围从 0x0000 000OxFFFF FFFF。 NULL指针分区范围:0x0000 0000-0x0000 FFFF作用:保护内存非法访问例子:分配内存时,如果由于某种原因分配不成功,则返回空指针0x0000 0000; 当用户继续使用比如改写数据时,系统将因为发生访问违规而退出。那么,为什么需要那么大的区域呢,“个地址值不就行了吗?我在想,是 不是因为不让8或16

3、位的程序运行于32位的系统上呢? !因为NULL分区刚 好范围是16的进程空间。 独享用户分区范围:0x0001 00000x7FFE FFFF作用:进程只能读取或访问这个范围的虚拟地址;超越这个范围的行为都会产 生违规退出。例子:程序的二进制代码中所用的地址大部分将在这个范围,所有exe和dll文 件都加载到这个。每个进程将近2G的空间是独享的。注意:如果在boot.ini上设置了/3G,这个区域的范围从2G扩大为3G: 0x0001 00000xBFFE FFFF。 共享内核分区范围:0x8000 00000xFFFF FFFF作用:这个空间是供操作系统内核代码、设备驱动程序、设备1/O高

4、速缓存、 非页面内存池的分配、进程目表和页表等。例子:这段地址各进程是可以共享的。注意:如果在boot.ini上设置了/3G,这个区域的范围从2G缩小为1G: OxCOOO 00000xFFFF FFFF 通过以上分析,可以知道,如果系统有n个进程,它所需的虚拟空间是: 2G*n+2G (内核只需2G的共享空间)。1.2 地址映射 区域区域指的是上述地址空间中的片连续地址。区域的大小必须是粒度(64k)的 整数倍,不是的话系统自动处理成整数倍。不同CPU粒度大小是不样的, 大部分都是64Ko区域的状态有:空闲、私有、映射、映像。在你的应用程序中,申请空间的过程称作保留(预订),可以用Virtu

5、alAlloc;删 除空间的过程为释放,可以用VirtualFree。在程序里预订了地址空间以后,你还不可以存取数据,因为你还没有付钱, 没有真实的RAM和它关联。这时候的区域状态是私有;默认情况下,区域状态是空闲:当exe或DLL文件被映射进了进程空间后,区域状态变成映像;当一般数据文件被映射进了进程空间后,区域状态变成映射。 物理存储器Windows各系列支持的内存上限是不样的,从2G到64G不等。理论上32 位CPU,硬件上只能支持4G内存的寻址;能支持超过4G的内存只能靠其他 技术来弥补。顺便提,下,Windows个人版只能支持最大2G内存,Intel使用 Address Window

6、s Extension (AWE)技术使得寻址范围为236=64G=当然,也得 操作系统配合。内存分配的最小单位是4K或8K, -一般来说,根据CPU不同而不同,后 面你可以看到可以通过系统函数得到区域粒度和页面粒度。 页文件页文件是存在硬盘上的系统文件,它的大小可以在系统属性里面设置,它相当 于物理内存,所以称为虚拟内存。事实上,它的大小是影响系统快慢的关键所 在,如果物理内存不多的情况下。每页的大小和上述所说内存分配的最小单位是样的,通常是4K或8K。 访问属性物理页面的访问属性指的是对页面进行的具体操作:可读、可写、可执行。CPU 一般不支持可执行,它认为可读就是可执行。但是,操作系统提

7、供这个可执行 的权限。PAGE_NOACCESS PAGE_READONLY PAGE_READWRITE PAGE_EXECUTE PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE 这6个属性很好理解,第一个是拒绝所有操作,最后一个是接受收有操作; PAGE_WRITECOPYPAGE_EXECUTE_WRITECOPY这两个属性在运行同一个程序的多个实例时非常有用;它使得程序可以共享代 码段和数据段。一般情况下,多个进程只读或执行页面,如果要写的话,将会 Copy页面到新的页面。通过映射exe文件时设置这两个属性可以达到这个目 的。PAGE_NOCACHEP

8、AGE WRITECOMBINE这两个是开发设备驱动的时候需要的。PAGE GUARD当往页面写入个字节时,应用程序会收到堆栈溢出通知,在线程堆栈时有用。映射过程进程地址空间的地址是虚拟地址,也就是说,当取到指令时,需要把虚拟地址 转化为物理地址才能够存取数据。这个工作通过页目和页表进行。页表:111024102410241页目:从图中可以看出,页目大小为4K,其中每项(32位)保存个页表的物理地 址;每个页表大小为4K,其中每项(32位)保存一个物理页的物理地址, 共有1024个页表。利用这4K+4K*1K=4.4M的空间可以表示进程的1024*1024* (页4K) =4G的地址空间。进程

9、空间中的32位地址如下:高10位中10位低12位高10位用来找到1024个页目项中的项,取出页表的物理地址后,利用中!0位来得到页表项的值,根据这个值得到物理页的地址,由于页有4K大小, 利用低12位得到单元地址,这样就可以访问这个内存单元了。每个进程都有自己的个页目和页表,那么,刚开始进程是怎么找到页目 所在的物理页呢?答案是CPU的CR3寄存器会保存当前进程的页目物理地址。当进程被创建时,同时需要创建页目和页表,一共需要4.4M。在进程的 空间中,OxCO3O 00000xC030 OFFF是用来保存页目的4k空间。OxCOOO 00000xC03F FFFF是用来保存页表的4M空间。也就

10、是说程序里面访问这些 地址你是可以读取页目和页表的具体值的(要工作在内核方式下)。有一点我 不明白的是,页表的空间包含了页目的空间!至于说,页目和页表是保存在物理内存还是页文件中,我觉得,页目比较 常用,应该在物理内存的概率大点,页表需要时再从页文件导入物理内存中。页目项和页表项是个32位的值,当页目项第位为1时,表明页表已 经在物理内存中;当页表项第位为1时,表明访问的数据已经在内存中。还 有很多数据是否已经被改变,是否可读写等标志。另外,当页目项第7位为1 时,表明这是个4M的页面,这值已经是物理页地址,用虚拟地址的低22 位作为偏移量。还有很多:数据是否已经被改变、是否可读写等标志。1.

11、3 个例子 编写生成软件程序exe软件描述如下:Main ()(1:定义全局变量2:处理函数逻辑(Load所需DLL库,调用方法处理逻辑)3:定义并实现各种方法(方法含有局部变量)4:程序结束将程序编译,生成exe文件,附带所需的DLL库。 exe文件格式exe文件有自己的格式,有若干节(section) : .text用来放二进制代码(exe 或dll) ; .data用来放各种全局数据。.text指令 1 : move a, b指令 2: add a, b.data数据1: a=2数据2: b=l这些地址都是虚拟地址,也就是进程的地址空间。 运行exe程序建立进程:运行这个exe程序时,系

12、统会创建一个进程,建立进程控制块 PCB,生成进程页目和页表,放到PCB中。数据对齐:数据的内存地址除以数据的大小,余数为时说明数据是对齐 的。现在的编译器编译时就考虑数据对齐的问题,生成exe文件后,数据 基本上是对齐的,CPU运行时,寄存器有标志标识CPU是否能够自动对 齐数据,如果遇到不能对齐的情况,或者通过两次访问内存,或者通知操 作系统处理。要注意的是,如果数据没有对齐,CPU处理的效率是很低的。文件映射:系统不会将整个exe文件和所有的DLL文件装载进物理内存中, 同时它也不会装载进页面文件中。相反,它会建立文件映射,也就是利用 exe本身当作页面文件。系统将部分二进制代码装载进内

13、存,分配页面给 它。假设分配了一个页面,物理地址为0x0232 FFF1。其中装载的个指 令虚拟地址为 0x4000 1001=0100 0000 00 0000 0000 01 0000 0000 0001 个页面有4K,系统会将指令保存在低12位0x0001的地址处。同时,系统 根据高10位0x0100找到页目项,如果没有关联的页表,系统会生成一个 页表,分配个物理页;然后,根据中10位0x0001找到表项,将物理地 址0x0232 FFF!存进去。执行过程:执行时,当系统拿到个虚拟地址,就根据页目和页表找到数据的地址, 根据页目上的值可以判断页表是在页文件中还是在内存中;如果在页文件中,

14、会将页面导入内存,更新页目项。读取页表项的值后, 可以判断数据页文件中还是在物理内存中;如果在页文件中,会导入到内 存中,更新页表项。最终,拿到了数据。在分配物理页的过程中,系统会根据内存分配的状况适当淘汰暂时不 用的页面,如果页面内容改变了(通过页表项的标志位),保存到页文件 中,系统会维护内存与页文件的对应关系。由于将exe文件当作内存映射文件,当需要改变数据,如更改全局变量的 值时,利用Copy-On-Write的机制,重新生成页文件,将结果保存在这个 页文件中,原来的页文件还是需要被其他进程实例使用的。在清楚了指令和数据是如何导入内存,如何找到它们的情况下,剩下 的就是CPU不断的取指

15、令、运行、保存数据的过程了,当进程结束后,系 统会清空之前的各种结构、释放相关的物理内存和删除页文件。2 .内存状态査询函数2.1 系统信息Windows提供API可以查询系统内存的些属性,有时候我们需要获取些页 面大小、分配粒度等属性,在分配内存时用的上。请看以下C+程序:SYSTEMJNFO syslnfo;GetSystemInfo(&sysInfo);coutvv”机器属性: vvendl;coutvv页 大小sysInfo.dwPageSizevvendl;cout”分酉己粒度二sysInfo.dwAllocationGranularityvvendl;cout”用户区最小值=sys

16、Info.lpMinimumApplicationAddressendl;cout”用户区最大值=”sysInfo.lpMaximumApplicationAddressendlendI;结果如下:负大小=4096分配粒廬=65536用户区曇值=00010000用户区最大值=7FFEFFFF可以看出,页面大小是4K,区域分配粒度是64K,进程用户区是0x000100000x7FFE FFFF。2.2 内存状态内存状态可以获取总内存和可用内存,包括页文件和物理内存。 请看以下C+程序:MEMORYSTATUS memStatus;GlobalMemoryStatus(&memStatus);co

17、utvv”内存初始状态:“ vvendl;coutvv” 内存繁忙程度二 vvmemStatus.dwMemoryLoadvvendl;coutvv”总物理内存=vvmemStatus.dwTotalPhysvvendl;coutvv”可用物理内 d=,memStatus.dwAvailPhysendl;coutvv”总页文件二 vvmemStatus.dwTotalPageFilevvendl;cout,rnj 用页文件二 vvmemS tatus.d w A vai 1 PageFileendl;coutvv”总进程空间二” vvmemStatus.dwTotalVirtuakvendl;

18、coutvv” 可用进程空间二” vvmemStatus.dwAvailVirtualvvendkvendl; 结果如下:2 0 7 8 4 0 6 2 0 4 4 7 4 4 5 2 0 5 1 7 2 19 2 2 15 9 5 5 4 0 0 2 3 3 2 2 2 10 8 7 1 5 7 5 7 5 4 2 .=0 = 791 = 态度=1存57=1=2间 薈存内=2在空 始忙内理件文空程 初繁理物文豊进 存居用 内内总司总可总可可以看出,总物理内存是1G,可用物理内存是510兆,总页文件是2.5G,这个 是包含物理内存的页文件;可用页文件是1.9G。这里还标识了总进程空间,还有 可

19、用的进程空间,程序只用了 22兆的内存空间。这里说的都是大约数。内存繁忙程序是标识当前系统内存管理的繁忙程序,从。到100,其实用处不大。在函数里而静态分配些内存后,看看究竟发生什么char statf65536;MEMORYSTATUS memStatus 1;GlobalMemoryStatus(&memStatus 1);coutvv”静态分配空间:nendl;printf(”指针地址二x/n”,stat);coutv”减少物理内存二” vvmemStatus.dwAvailPhys-memStatusl.dwAvailPhysvvendl;coutv减少可用页文件=,memStatus

20、.dwAvailPageFile-memStatusl.dwAvailPageFileendl;coutvv”减少可用进程空间 vvmemStatus.dwAvailVirtuamemSta tusl.dwAvailVirtualendlendl;结果如下:C=0间 :e0=0件空 间2f存文程 空=1受进 配址理用用 分地物可可 态针少少少 建减减减可以看出,物理内存、可用页文件和进程空间都没有损耗。因为局部变量是分配 在线程堆栈里面的,每个线程系统都会建立一个默认1M大小的堆栈给线程函数 调用使用。如果分配超过1M,就会出现堆栈溢出。 在函数里面动态分配300M的内存后,看看究竟发生什么c

21、har *dynamic=new char300* 1024* 1024;MEMORY ST ATUS memStatus2;GlobalMemoryStatus(&memStatus2);coutvv”动态分配空间:nendl;printf(指针地址二x/n”,dynamic);coutvv”减少物理内存=nmemStatus.dwAvailPhys-memStatus2.dwAvailPhysendl;coutvv”减少可用页文件=,memStatus.dwAvailPageFile-memStatus2.dwAvailPageFileendl;coutvv”减少可用进程空间=,memSt

22、atus.dwAvailVirtuaI-memStatus2.dwAvailVirtualendlendl;结果如下:指 针地址=105 40040减少物理内存=315551744 减少可用页文件=315518976減少可用进程空间=314576896动态分配情况下,系统分配直到内存页文件使用完为止,当然,系统要留下系 统使用的页面。2.3进程区域地址査询在给定一个进程空间的地址后,可以查询它所在区域和相邻页面的状态,包括页 面保护属性、存储器类型等。 C+静态分配了两次内存,一次是4K大一点,个是900K左右。char arrayA 4097;char arrayB 900000;第一次查询

23、:long len=sizeof(MEMORY_BASICJNFORMATION);MEMORY_BASICNFORMATION mbiA;VirtualQuery(arrayA,&mbiA,len);coutv v”静态内存地址属性: vvendl;coutvv”区域基地址二 vvmbiA.AHocationBasevvendl;coutvv”区域邻近页面状态=” vvmbi A.State vvendl;coutvv”区域保护属性=”vvmbiA.AllocationProtectvvendl;coutvv”页面基地址二” vvmbiA.BaseAddressvvendl;printf(n

24、arrayA 指针地址二x/n”,array A);coutv V”从页面基地址开始的大小二”号mbi A. RegionSizevvendl;cout”邻近页面物理存储器类型二”mbiA.Typevvendl;cout”页面保护属性二”mbiA.Protectendlendl;第二次查询:MEMORY_BASICNFORMATION mbiB;VirtuaIQuery(arrayB,&mbiB,len);cout”静态内存地址属性:”endl;cout”区域基地址二”mbiB.AllocationBasevvendl;cout”区域邻近页面状态二”mbiB.Statevvendl;cout”

25、区域保护属性二”mbiB.AllocationProtectvvendl;cout”页面基地址二”mbiB.BaseAddressvvendl;printf(arrayB 指针地址二x/n”,arrayB);cout”从页面基地址开始的大小二”mbiB.RegionSizevvendl;cout邻近页面物理存储器类型=mbiB.Typeendl;cout页面保护属性=mbi B.Protectendlendl;说明:区域基地址指的是给定地址所在的进程空间区域;邻近页面状态指的是与给定地址所在页面状态相同页面的属性:MEM_FREE(空 闲=65536)、MEM_RESERVE (保留=8192

26、)和 MEM_COMMIT (提交=4096) 区域保护属性指的是区域初次被保留时被赋予的保护属性:PAGE_READONLY(2)、PAGE_READWRITE (4)、PAGE_WRITECOPY (8)和PAGE_EXECUTE_WRITECOPY (128)等等。页面基地址指的是给定地址所在页面的基地址。从页面基地址开始的区域页面的大小,指的是与给定地址所在页面状态、保护属 性相同的页面。邻近页面物理存储器类型指的是与给定地址所在页面相同的存储器类型,包括: MEM_PRIVATE (页文件=131072) MEM_MAPPED (文件映射=262144)和 MEM_IMAGE (ex

27、e 映像=16777216) 页面保护属性指的是页面被指定的保护属性,在区域保护属性指定后更新。结果如下:“区区区页 静区区区页属00状=401址开存=4 址=0面性=0地址理性 地址賈址 靠近护地指基面护 内基邻保基W面页保 态域域域面ra页近面性40态004094小型00 e内皆 0 2F32E=1始储性40态53=5始储 属00状=400址开存=4 址=0面性=0地址理性 地址置址気闇 壶近护地指基面护 内基邻保基VB面页保 态域域域面raK近面00409如前所说,这是在堆栈区域0x0004 0000里分配的,后分配的地址arrayB反而更 小,符合堆栈的特性。arrayA和arrayB

28、它们处于不同的页面。页面都受页文件 支持,并且区域都是提交的,是系统在线程创建时提交的。 C+动态分配了两次内存,一次是1K大一点,个是64K左右。所以应该 不会在个区域。char *dynamicA=new char1024;char *dynamicB=new charf65467;VirtuaIQuery(dynamicA,&mbiA,len);coutn动态内存地址属性:nendl;coutvv”区域基地址=vmbiA.AllocationBasevvendl;coutH 区域邻近页面状态=mbi A.Stateendl;coutv”区域保护属性 vvmbiA.AHocationPro

29、tectvvendl;coutvv”页面基地址=vmbiA.BaseAddressvvendl;printf(ndynamicA 指针地址二x/n”,dynamicA);coutvv”从页面基地址开始的大小二” vvmbiA.RegionSizevvendl;coutvv”邻近页而物理存储器类型二 vvmbiA.Typevvendl;coutn 页面 保护属 性=vvmbiA.Protectv vendk vendl;VirtualQuery(dynamicB,&mbiB,len);coutvv”动态内存地址属性:” vvendl;coutvv”区域基地址二” vvmbiB.AHocation

30、Basevvendl;coutvv”区域邻近页面状态二” vvmbiB.Statevvendl;coutvv” 区域保护 属性二” vvmbiB.AllocationProtectvvendl;coutvv” 页面基地址二” vvmbiB.BaseAddressvvendl;printf(dynamicB 指针地址二x/n”,dynamicB);coutvv”从页面基地址开始的大小二” vvmbiB.RegionSizevvendl;coutvv”邻近页面物理存储器类型二” vvmbiB.Typevvendl;coutn 页面保护属性二” vvmbi B. Protectv vendl;结果如

31、下:态域域域面na页近面内基邻保基mi面页保拿近护地CA基面护属00状=400地开存=4 址=0面性=0苴理性 地址址指地鷲性30态aw 0 9 4/4 -0 3勺S 0 =自口 39址始储个=8192 型=131072态域域域面na页近面内基邻保基mi面血保近护地CB基面护属0E状=40E地开存=4 址=0面性=0基理性 地址費址指地闇性10态0601 0 14/4- 00=e的器 10址始储236 9这里是动态分配,dynamicA和dynamicB处于两个不同的区域;同样,页面都受 页文件支持,并且区域都是提交的。第二个区域是比64K大的,由分配粒度可知,区域至少是128K。那么,剩下的

32、 空间也是提交的吗,如果是的话那就太浪费了。看看就知道了: 0x00E2 1000 n 定在这个空间里,所以查询如下:VirtualQuery(char*)0xE23390,&mbiB,len);cout动态内存地址属性:endl;cout区域 基地址=mbi B. Al locationBaseendl;cout区域邻近页面状态=mbiB.Stateendl;cout区域保护 属性=mbiB.AHocationProtectendl;cout页面基地址=mbi B. BaseAddressendl;printf(dynamicB 指针地址=%x/n,0xE2100);cout从页面基地址开始

33、的大小=mbiB.RegionSizeendl;cout邻近页面物理存储器类型=mbiB.Typeendl;cout页面保护属性=mbi B.Protectendl;结果如下:属0E状=40E地开存=0 址=0面性=0基理性 地址畫址指地闇 拿近护地CB基面护 内基邻保基mi面页保 态域域域面na页近面 区区页My从矇性10态21址始储00的器0 = 00! 0 2.可以看出,邻近页面状态为保留,还没提交,预料之中;OxOOEl 0000这个区域 的大小可以计算出来:69632+978944=1024Ko系统动态分配了 1M的空间,就 为了 64K左右大小的空间。可能是为了使得下次有要求分配时

34、时不用再分配了。3.内存管理机制一虚拟内存(VM) 虚拟内存使用场合虚拟内存最适合用来管理大型对象或数据结构。比如说,电子表格程序,有很多 单元格,但是也许大多数的单元格是没有数据的,用不着分配空间。也许,你会 想到用动态链表,但是访问又没有数组快。定义二维数组,就会浪费很多空间。 它的优点是同时具有数组的快速和链表的小空间的优点。 分配虚拟内存如果你程序需要大块内存,你可以先保留内存,需要的时候再提交物理存储器。 在需要的时候再提交能有效的利用内存。一般来说,如果需要内存大于1M, 用虚拟内存比较好。 保留用以下Windows函数保留内存块VirtualAlloc(PVOID 开始地址,SI

35、ZE_T 大小,DWORD 类型,DWORD 保护属 性)一般情况下,你不需要指定“开始地址,因为你不知道进程的那段空间是不是已 经被占用了;所以你可以用NULL。“大小”是你需要的内存字节;“类型”有 MEM_RESERVE (保留)、MEM.RELEASE (释放)和 MEM.COMMIT (提交)。 “保护属性”在前面章节有详细介绍,只能用前六种属性。如果你要保留的是长久不会释放的内存区,就保留在较高的空间区域,这样不会 产生碎片。用这个类型标志可以达到;MEM RESERVEIMEM TOP DOWN C+程序:保留1G的空间LPVOIDpV=VirtualAlloc(NULL,l 0

36、00*1024*1024,MEM_RESERVEIMEM_TOP_DOWN, PAGE_READWRITE);if(pV=NULL)cout没有那么多虚拟空间!endl;MEMORYSTATUS memStatusVirtual 1;GlobalMemoryStatus(&memStatusVirtual 1);cout虚拟内存分配:endl;printf(指针地址=%x/n,pV);cout减少物理内存=memStatusVirtual.dwAvailPhys-memStatus Virtual 1 .dwAvailPhysendl;cout减少可用页文件=memStatusVirtual.

37、dwAvailPageFile-memStatusVirtuall .dwAvaiIPageFilee ndl;cout减少可用进程空间=memStatusVirtual.dwAvailVirtual-memStatusVirtuall .dwAvailVirtualendl endl;结果如下:配41存文程 分=2亨逬 盘理用用 内地物可可 虚指减减减C63=2间=1呈可见,进程空间减少了 1G;减少的物理内存和可用页文件用来管理页目和页表。 但是,现在访问空间的话,会出错的:int * iV=(int*)pV;/iV01= 1;现在访问会出错,出现访问违规你必须提供个初始地址和提交的大小。

38、提交的大小系统会变成页面的倍数,因 为只能按页面提交。指定类型是MEM_COMMIT。保护属性最好跟区域的保护 属性一致,这样可以提高系统管理的效率。C+程序:提交100M的空间LPVOIDpP=VirtualAlloc(pV,l 00* 1024* 1024,MEM_COMMIT,PAGE_READWRITE);if(pP=NULL)cout没有那么多物理空间!”endl;int * iP=(int*)pP;iP0=3;iP 100/sizeof(int)* 1024* 1024-1=5;这是能访问的最后个地址/iPl 00/sizeof(int)*l024* 1024=5;访问出错 保留&

39、提交你可以用类型MEM_RESERVEIMEM_COMMIT 一次全部提交。但是这样的话, 没有有效地利用内存,和使用一般的C+动态分配内存函数一样了。 更改保护属性更改已经提交的页面的保护属性,有时候会很有用处,假设你在访问数据后,不 想别的函数再访问,或者出于防止指针乱指改变结构的目的,你可以更改数据所 处的页面的属性,让别人无法访问。VirtualProtect(PVOID 基地址,SIZE_T 大小,DWORD 新属性,DWORD 旧属性) “基地址”是你想改变的页面的地址,注意,不能跨区改变。C+程序:更改页的页面属性,改为只读,看看还能不能访问DWORD protect;iP0=8

40、;VirtualProtect(pV,4096,PAGE_READONLY,&protect);int * iP=(int*)pV;iP1024=9;可以访问,因为在那页之外iP0=9;不可以访问,只读还原保护属性VirtualProtect(pV,4096,PAGE_READWRITE,&protect);cout初始值=iPc(PVOID 开始地址,SIZE_T 大小,DWORD 类型,DWORD 保护属 性)“大小”如果小于个页面的话,函数会执行失败,因为系统使用四舍五入的方法;“类型,是 MEM_RESETo有人说,为什么需要清除呢,释放不就行了吗?你要知道,释放了后,程序就无 法访问

41、了。现在只是因为不需要结构的内容了,顺便提高一下系统的性能;之后 程序仍然需要访问这个结构的。C+程序:清除1M的页面:PVOIDre=VirtuaiAlioc(pV, 1024*1024,MEM_RESET,PAGE_READWRITE); if(re=NULL)cout清除失败! ”endl;这时候,页面可能还没有被清零,因为如果系统没有RAM请求的话,页面内存 保存不变的,为了看看被清零的效果,程序人为的请求大量页面: C+程序:VirtualAlloc(char*)pV+100*1024* 1024+4096,memStatus.dwAvailPhys+1000000 ,MEM_COM

42、Mrr,PAGE_READWRITE); 没访问之前是不给物理内存的。char* pp=(char*)pV+100* 1024* 1024+4096;for(int i=O;imemStatus.dwAvailPhys+10000000;i+)PPi=V;逼他使用物理内存,而不使用页文件 GlobalMemoryStatus(&memStatus);cout内存初始状态:endl;cout-|x;Jx=memStatus.dwLengthendl;cout”内存繁忙 程度=memStatus.dwMemoryLoadendl;cout总物理内 #=memStatus.dwTotalPhysen

43、dl;cout可用物理内 ir=memStatus.dwAvailPhysendl;cout“总页文件=memStatus.dwTotaIPageFileendl;cout”可用页文件=memStatus.dwAvailPageFileendl;cout”总进程空间=memStatus.dwTotalVirtualendl;cout可用进程空间=memStatus.dwAvailVirtualend;cout清除后=iP endl;结果如下:6 4 ? 8 6 8 6 1 0 6 0 7 4 4 7 2 0 5 3 7 7 19 2 6 19 9 15 5 0 0 2 8 3 7 3 2 0

44、0 3 7 0 :=507=577641 4=1 态度=1存57=1=2间 状程存内=2空 =8始2忙内理件文空程 鳴=3聲理物文豊逬 始存豊覇用 初内长内总可总可总可态 6 rtr =0 = 711 = 的度=1存57=1=2间 时程存内=2舊空 零2忙内理件文空程=0 清=3繁理物文矗逬后 入豊爲 逬长内总可总可总可清当内存所剩无儿时,系统将刚清除的内存页面分配出去,同时不会把页面的内存 写到虚拟页面文件中。可以看见,原先是8的值现在是。 了。 虚拟内存的关键之处虚拟内存存在的优点是,需要的时候真正分配内存。那么程序必须决定何时 提交内存。如果访问没有提交内存的数据结构,系统会产生访问违规

45、的错误。提交的最好方 法是,当你程序需要访问虚拟内存的数据结构时,假设它已经是分配内存的,然 后异常处理可能出现的错误。对于访问违规的错误,就提交这个地址的内存。释放可以释放整个保留的空间,或者只释放分配的些物理内存。释放特定分配的物理内存:如果不想释放所有空间,可以只释放某些物理内存。“开始地址”是页面的基地址,这个地址不一定是第一页的地址,个窍门是提供 页中的某个地址就行了,因为系统会做页边界处理,取该页的首地址;“大小 是页面的要释放的字节数;“类型”是MEM.DECOMMIToC+程序:只释放物理内存VirtualFree(int*)pV+2OOO,5O* 1024* 1024,MEM

46、_DECOMMIT);int* a=(int*)pV;a10=2,可以使用,没有释放这页MEMORYSTATUS memStatusVirtual3;GlobalMemoryStatus(&memStatusVirtual3);cout物理内存释放:endl;cout增加物理内存=,memStatusVirtual3.dwAvailPhys-memStatusVirtual2.dwAvailPhysendl; cout增加可用页文件=memStatusVirtual3.dwAvailPageFile-memStatusVirtual2.dwAvailPageFile endl;cout 增加可

47、用进程空间memStatusVirtual3.dwAvailVirtual-memStatusVirtual2.dwAvailVirtualendl endl;结果如下:9543029=5间 .=4件空 放存文程 釋受进 存理用用可可 理加加加可以看见,只释放物理内存,没有释放进程的空间。释放整个保留的空间:VirtualFree (LPVOID 开始地址,SIZE.T 大小,DWORD 类型) “开始地址” 定是该区域的基地址;“大小必须是,因为只能释放整个保留的 空间;“类型”是MEMRELEASE。C+程序:VirtualFree(pV,O,MEM_RELEASE);a10=2;不能使用

48、了,进程空间也释放了MEMORYSTATUS memStatusVirtual4;GlobalMemoryStatus(&memStatusVirtual4);cout虚拟内存释放:“endl;cout增加物理内存=memStatusVirtual4.dwAvailPhys-memStatusVirtual3.dwAvailPhys endl; cout增加可用页文件=,memStatusVirtual4.dwAvailPageFile-memStatusVirtual3.dwAvailPageFile endl;cout”增加可用进程空间memStatusVirtual4.dwAvailVi

49、rtual-memStatusVirtual3.dwAvailVirtualendl endl;结果如下:塵拟内存释放:憎加物理百存=660623360増加可用页文件=725204992增加可用逬程空间=1048576000整个分配的进程区域被释放了,包括所占的物理内存和页文件。何时释放如果数组的元素大小是小于一个页面4K的话,你需要记录哪些空间不需要,哪 些在个页面上,可以用个元素一个Bit来记录;另外,你可以创建一个线程 定时检测无用单元。扩展地址AWEAWE是内存管理器功能的套应用程序编程接口(API),它使程序能够将物理 内存保留为非分页内存,然后将非分页内存部分动态映射到程序的内存工

50、作集。 此过程使内存密集型程序(如大型数据库系统)能够为数据保留大量的物理内存, 而不必交换分页文件以供使用。相反,数据在工作集中进行交换,并且保留的内 存超过4 GB范围。对于物理内存小于2G进程空间时,它的作用是:不必要在物理内存和虚拟页文 件中交换。对于物理内存大于2G进程空间时,它的作用是:应用程序能够访问的物理内存 大于2G,也就相当于进程空间超越了 2G的范围;同时具有上述优点。3GB当在boot.ini上加上/3GB选项时,应用程序的进程空间增加了 1G,也就是说, 你写程序时,可以分配的空间又增大了 1G,而不管物理内存是多少,反正有虚 拟内存的页文件,大不了慢点。PAE当在b

51、oot.ini上加上/PAE选项时,操作系统可以支持大于4G的物理内存,否则, 你加再多内存操作系统也是不认的,因为管理这么大的内存需要特殊处理。所以, 你内存小于4G是没有必要加这个选项的。注意,当要支持大于!6G的物理内存 时,不能使用/3G选项,因为,只有1G的系统空间是不能管理超过16G的内存 的。AWE当在boot.ini上加上/AWE选项时,应用程序可以为自己保留物理内存,直接的 使用物理内存而不通过页文件,也不会被页文件交换出去。当内存大于3G时, 就显得特别有用。因为可以充分利用物理内存。当物理内存大于4G时,需要/PAE的支持。以下是个boot.ini的实例图,是我机器上的:

52、r boot.ini - Notepad :j XFile Edit Format View Helpboot loadertimeout=30default二multi(0)disk(O)rdisk(O)partition(1)windowsoperating systemsmulti(0)disk(O)rdisk(O)partition(1) wiNDOWS=Mi crosoft wi ndows xp Professional /noexecute=optin /fastdetect /3gb /pae /awe要使用AWE需要用户具有Lock Pages in Memory权限,这个在

53、控制面板中的 本地计算机政策中设置。第一,分配进程虚拟空间:VirtualAlloc(PVOID 开始地址,SIZE_T 大小,DWORD 类型,DWORD 保护属 性)“开始地址”可以是NULL,由系统分配进程空间;“类型”是MEM_RESERVEIMEM_PHYSICAL; “保护属性,只能是PAGE_READWRITEoMEM_PHYSICAL指的是区域将受物理存储器的支持。第二,你要计算出分配的页面数目PageCount:利用本文第二节的GetSystemlnfo可以计算出来。第三,分配物理内存页面:AllocateUserPhysicalPages (HANDLE 进程句柄,SIZE

54、_T 页数,ULONG_PTR 页 面指针数组)进程句柄可以用GetCurrentProcess。获得;页数是刚计算出来的页数PageCount; 页面数组指针 unsigned long* ArrayfPageCount系统会将分配结果存进这个数组。第四,将物理内存与虚拟空间进行映射:MapUserPhysicalPages(PVOID 开始地址,SIZE_T 页数,ULONG_PTR 页面指针 数组)“开始地址是第一步分配的空间; 这样的话,虚拟地址就可以使用了。 如果“页面指针数组是NULL,则取消映射。 第五,释放物理页面FreeUserPhysicalPages (HANDLE 进程

55、句柄,SIZE_T 页数,ULONG_PTR 页面指 针数组)这个除了释放物理页面外,还会取消物理页面的映射。第六,释放进程空间VirtualFree(PVOID 开始地址,, MEM_RELEASE)C+程序:首先,在登录用户有了 Lock Pages in Memory权限以后,还需要调用Windows API 激活这个权限。BOOL VirtualMem:LoggedSetLockPagesPrivilege ( HANDLE hProcess,BOOL bEnable) (struct DWORD Count;数组的个数LUID_AND_ATTRIBUTES Privilege 1;

56、Info;HANDLE Token;打开本进程的权限句柄BOOL Result = OpenProcessToken ( hProcess,TOKEN_ADJUST_PRIVILEGES,& Token);If(Result!=TRUE)printf( Cannot open process token./n);return FALSE;我们只改变个属性Info.Count = 1;准备激活if( bEnable )Info.Privilege0.Attributes = SE_PRIVILEGE_ENABLED;elseInfo.Privilege0. Attributes = 0;根据权限

57、名字找到LGUIDResult = LookupPrivilegeValue ( NULL,SE_LOCK_MEMORY_NAME,&(Info.Privilege0.Luid);if( Result != TRUE )printf( Cannot get privilege for %s./n, SE_LOCK_MEMORY_NAME ); return FALSE;)激活 Lock Pages in Memory 权限Result = AdjustTokenPrivileges ( Token, FALSE,(PTOKEN_PRIVILEGES)&lnfo,0, NULL, NULL);i

58、f( Result != TRUE )printf (Cannot adjust token privileges (%u)/n, GetLastError();return FALSE;else(if( GetLastErrorO != ERROR_SUCCESS )Iprintf (Cannot enable the SE_LOCK_MEMORY_NAME privilege; );printf (please check the local policy./n);return FALSE;CloseHandle( Token );return TRUE;分配100M虚拟空间:PVOIDp

59、Virtual=VirtualAlloc(NULL, 100* 1024* 1024,MEM_RESERVEIMEM_PHYSICA L,PAGE_READWRITE);if(pVirtual=NULL)cout没有那么大连续进程空间!endl;MEMORYSTATUS memStatusVirtual5;GlobalMemoryStatus(&memStatusVirtual5);coutvv”虚拟内存分配:nendl;coutv减少物理内存=nmemStatusVirtual4.dwAvailPhys-memStatusVirtual5.dwAvailPhysendlcoutvv”减少可用

60、页文件=memStatusVirtual4.dwAvailPageFile-memStatusVirtual5.dwAvailPageFile endl;coutvv”减少可用进程空间memStatusVirtual4.dwAvailVirtual-memStatusVirtual5.dwAvailVirtualendlendl;结果如下:0 0656 89 48 8 00 8 16 0 =96=2间 .=1件空 配存文程 分逬 存理用用可以看见,只分配了进程空间,没仃分配物理内存。分配物理内存:ULONG.PTR pages=(ULONG_PTR) 100* 1024* 1024/sysInfo.dwPageSize;ULONG_PTR *frameArray=new ULONG_PTR pages;如果没激活权限,是不能调用这个方法的,可以调用,但是返回FALSE BOOL flag=AllocateUserPhysicalPages(GetCurrentProces

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!