《windows核心编程》 在应用程序中使用虚拟内存
Microsoft Windows 提供了以下三种机制来对内存进行操控:
- 虚拟内存 最适合用来管理大型对象数组或大型结构数组
- 内存映射文件 最适合用来管理大型数据流(通常是文件),以及在同一台机器上运行多个进程之间共享数据
- 堆 最适合管理大量小型对象
本篇只讨论第一种方式 虚拟内存。
15.1 预订地址空间区域
可以使用VirtualAlloc函数来预订进程中的地址空间区域
LPVOID WINAPI VirtualAlloc(
__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect
);
lpAddress :想要预订地址空间的哪一块,如果要在进程地址空间第50MB的地方分配区域。我们要传52 428 800(50*1024*1024)给pvAddress参数。系统始终按分配粒度的整数倍来分配的因此如果我们想要在19668992(300*65536+8192)的地方预订区域,那么系统会向下取整到64整数倍,也就是19660800(300*65536)然后取整后的地址预订区域。如果VirtualAlloc能满足我们的要求,那么它会预订一块区域并返回该区域的基地址。如果我们还给pvAddesss指定了参数,那么,它的返回值就等于我们传给pvASddress参数值向下取整到64KB的整数倍dwSize: 指定我们想要分析区域的大小,以字节为单位。由于系统始终都根据cpu页面大小整数倍来预订区域,因此如果我们的页面大小为4KB,8KB或16KB的机器上预订62 KB的区域的话,那么最终得到的区域大小为64KBflAllocationType:是预订区域还是调拨物理存储器,如果是预订就要传 MEM_RESERVE为参数如果打算预订一块区域,并且用很长时间,那我们可能会希望系统从尽可能高的内存地址来预订。这样可以防止进程地址空间的中间预订区域,从而避免可能会引起内存碎片。fdwProtect:给区域指定保护属性。如果应用程序在非统一内存访问的机器上运行,我们可以调用VirtualAllocExNuma函数来强制系统在某个节点的物理内存中分配一部分虚拟内存
15.2 给区域调拨物理存储器、
在预了区域之后,我们还需要给给区域调拨物理存储器,这样才能访问其中的内存地址。系统会从页交换文件中来调拨物理存储器给区域。在调拨物理存储器时,起始地址始终都是页面大小的整数倍,整个大小也是页面大小的整数倍调拨物理存储器,我们必须再次调用VirtualAlloc。但这次我们会传 MEM_COMMIT来作为第二个参数fdwAllocationType的值在已预订的区域中,我们“必须”告诉VirtualAlloc要调拨多少物理存储器给哪里。这是通过pvAddress和dwSize来指定的。前者表示想要调拨物理存储器给哪个内存地址,后来表示物理存储器的数量。以字节为单位。
15.3 同时预订和调拨物理存储器
PVOID pvMem = VirtualAlloc(NULL,99*1024,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE)
15.4 何时调拨物理存储器
何时调拨物理存储器是一个问题,例如我们正在实现一个电子表格的程序,它支持200行,256。如果一个单元格是一个CELLDATA结构的话,如果这一个结构頕128字节,那么这个二维数组需要 200 * 256 * 128 的字节的物理存储器。那么如果一打开程序就去调拨,明显会頕用大量的物理存储器。尤其是因为用户经常只用一两个单元格的时候,那么这种调拨方法明显是浪费虚拟内存技术为我们提供了方案:1.预订一块足够大的区域来容纳CELLDATA数组。只预订根本不会消耗物理存储器
2.当用户某个单元格输入数据时,首先确定CELLDATA的内存地址。当然没有调拨,会引发访问违规
3.给第二步中的内存地址调拨足够的物理存储器。
4.设置CELLDATA结构成员的内容
虚拟内存技术存在一个问题是:我们必须确定什么时候需要调拨物理存储器。有以下四种方法来确定是否需要给区域中的某一部分调拨物理存储器
1.总是尝试调拨,这种该当的缺点是每次对CELLDATA进行修改时,要多调用一次 VirtualAlloc。
2.使用VirtualQuery来判断是否给CELLDATA调拨过了。这种方法其实比第一种方法还糟糕:由于额外调用了VirtuaQuery函数,它不但增加了程序的大小,而且还降低了程序的性能
3.记录哪些被调拨过。这样来实时调拨
4.使用结构化异常处理------最佳方案。让程序底图方法内存异常的时候,调拨。
15.5 撤销缺氧物理存储器及释放区域
要撤销调拨给区域的物理存储器,或是释放地址空间中的一整块区域,可以调用VirtualFree函数。如果进程不再需要访问区域中的物理存储器,那么我们只需要调用VirtaulFree一次,就能够释放整个区域以及调拨给该区域的物理存储。我们必须传MEM_RELEASE给fdwFreeType来告诉系统撤销调拨给该区域的所有物理存储器,并释放区域。如果想要撤销区域的一部分,我们只需要给pvAddress传地址,然后dwSize传大小,fdwFreeType传MEM_DECOMMIT就行
15.5.1何时撤销调拨物理存储器
15.6 改变保护属性
15.7 改变物理存储器的内容
当我们修改物理存储页中的内容时,系统会尽量把改动保持在内存中。但是,当应用程序在运行的时候,系统可能需要从exe文件,或dll文件或页交换文件中载入新的页面到内存里。为了满足最近的载入请求,系统会在内存查找可用的页面,如果找到的页面已经被修改过,那么系统还必须将它们换出到页交换文件中。
Windows还提供了一种特性,一路使得应用程序能够提高中自身的性能-----这项特性就是重置物理存储器。重置物理存储器的意思是,我们告诉系统一个或几个物理存储页中的数据没有被修改过。如果系统正在查找一页闲置内存并且找到了一个修改过的页面,那么系统必须把该内存写入到页交换文件中。这个操作比较慢,会影响性能。对大多数应用程序来说,我们都希望系统把修改后的页面保存到页交换文件中。
但是,有些应用程序只需要在一小段时间内使用存储器,之后也不需要保留存储器中的内容。为了提高性能,应用程序可以告诉系统不要在页交换文件中保存指定存储器。这基本上是应用程序用来告诉系统一个页面未被修改过的一种方法。因此,如果系统决定将一个内存页挪作他用,好么它不会将页面内容保存到页交换文件中,这样提高了性能。为了重置存储器,应用程序应该调用VirtualAlloc函数,并在第三个参数中传MEM_RESET标志。
15.8 地址窗口扩展
地址窗口扩展特性:
1.允许应用程序以一种特殊的方式分配内存,操作系统保证不会将以这种方式分配的内存换出到磁盘上
2.允许应用程序访问比进程地址空间还要多的内存。
基本上 AWE提供了一种方式,可以让应用程序分配一块或多块内存。当一开始分配时,在进程的地址空间中是看不见这些内存块的应用程序然后预订地址空间区域,这就是地址窗口。应用程序然后调用一个函数,每调用一次把一块内存指定到该地址窗口。把内存块指定到地址窗口是非常快的。
//1.预订1MB地址空间
ULONG_PTR ulRAMBytes = * ;
PVOID pvWindow = VirtualAlloc(NULL,ulRAMBytes,
MEM_RESERVE | MEM_PHYSICAL ,PAGE_READWRITE); //2.得到当前平台的一个页面的大小
SYSTEM_INFO sinf;
GetSystemInfo(&sinf); //3.计算需要多少内存页
ULONG_PTR ulRAMPages = (ulRAMBytes + sinf.dwPageSize - ) / sinf.dwPageSize; //4.分配内存页数组、
ULONG_PTR * aRAMPages = (ULONG_PTR * ) new ULONG_PTR[ulRAMPages]; //5.分配物理存储器
AllocateUserPhysicalPages(GetCurrentProcess(),
&ulRAMPages,
aRAMPages); //6. 指定内存块指定给地址窗口
MapUserPhysicalPages(pvWindow,
ulRAMPages,
aRAMPages); //7.使用内存... //8.释放内存页块
FreeUserPhysicalPages(GetCurrentProcess(),
&ulRAMPages,
aRAMPages); VirtualFree(pvWindow,,MEM_RELEASE);
delete [] aRAMPages;
《windows核心编程》 在应用程序中使用虚拟内存的更多相关文章
- Windows核心编程:第14章 探索虚拟内存
Github https://github.com/gongluck/Windows-Core-Program.git //第14章 探索虚拟内存.cpp: 定义应用程序的入口点. // #inclu ...
- 《Windows核心编程系列》十三谈谈在应用程序中使用虚拟内存
在应用程序中使用虚拟内存 Windows提供了以下三种机制对内存进行操控: 一:虚拟内存.最适合来管理大型对象数据或大型结构数组. 二:内存映射文件.最适合用来管理大型数据流,以及在同一机 器上运行的 ...
- Windows核心编程 第十五章 在应用程序中使用虚拟内存
第1 5章 在应用程序中使用虚拟内存 Wi n d o w s提供了3种进行内存管理的方法,它们是: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常 ...
- 《Windows核心编程》第一讲 对程序错误的处理
一个Windows函数通常都有一个有意义的返回值类型,它标志着这个函数的运行状态,即函数运行成功与否.windows常用的函数类型如下图: 从系统内部来讲,当一个Windows函数检测到一个错误时,它 ...
- windows核心编程 第5章job lab示例程序 解决小技巧
看到windows核心编程 第5章的最后一节,发现job lab例子程序不能在我的系统(win8下)正常运行,总是提示“进程在一个作业里” 用process explorer程序查看 ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- windows核心编程---第二章 字符和字符串处理
使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也 ...
- 《Windows核心编程》第5版 学习进度备忘
学习资源:<Windows核心编程>第5版 知识基础支持: 本书与<Windows程序设计>第5版珍藏版结合很好,二者重叠内容不多,二者互补性强,而且相关方面的优秀书籍 跳过的 ...
随机推荐
- XAudio2播放PCM
XAudio2 是一个跨平台的API,在Xbox 360及Windows中得到支持.在Xbox 360上, XAudio2作为一个静态库编译到游戏可执行文件中.在Windows上,XAudio2提供一 ...
- APscheduler总结
APscheduler使用总结 APscheduler是执行定时任务的python库,其作用可以代替Linux系统下的crontab,github上有该库的例子. APsheduler基本使用 该模块 ...
- Windows8 上用Ubuntu-Ubuntu启动SSH
公司刚给配了一个电脑,华硕的超级本8个G的内存,很强大的了,但是系统是64位的windows 8,我用wubi.exe直接安装到系统上,但是开机启动的时候总是下面这个错误,去Ubuntu社区请教,结论 ...
- (18)PL/SQL
PL/SQL(Procedure Language/SQL) PL/SQL是Oracle对sql语言的过程化扩展---指在sql命令语言中增加了过程处理语句(如分支.循环等),使sql语言具有过程处理 ...
- (13)C#数组
如果需要使用同一类型的多个对象,数组是一种数据结构,它包含同一类型的多个元素 一.一维数组 1.数组的声明方法 int [] a; 因为数组是引用类型,引用类型有个特点是:声明变量时不会马上分配一个内 ...
- luogu P1195 口袋的天空
题目背景 小杉坐在教室里,透过口袋一样的窗户看口袋一样的天空. 有很多云飘在那里,看起来很漂亮,小杉想摘下那样美的几朵云,做成棉花糖. 题目描述 给你云朵的个数N,再给你M个关系,表示哪些云朵可以连在 ...
- POJ 3470 Walls(线段树+扫描线)
[题目链接] http://poj.org/problem?id=3470 [题目大意] 给出几面墙,均垂直于x轴或者y轴,给出一些鸟的位置(二维坐标点), 鸟只会垂直x轴或者y轴飞行,并且会撞上最近 ...
- [CF617E]XOR and Favorite Number/[CQOI2018]异或序列
题目大意: 给定一个长度为$n(n\leq10^5)$的数列$A$和数$k$$(A_i,k\leq10^6)$.$m$组询问,每次询问区间$[l,r]$中有多少对$i,j(l\leq i\leq j\ ...
- AHOI 2009 中国象棋
题面 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走 ...
- Java字符串(String)
从表面上看,字符串就是双引号之间的数据,例如“微学苑”.“http://www.weixueyuan.net”等.在Java中,可以使用下面的方法定义字符串: String stringName ...