Windows核心编程小结3
内存映射和堆栈
内存映射文件
内存映射文件可以用于3个不同的目的:
系统使用内存映射文件,以便加载和执行.exe和DLL文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。
可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。
可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。Windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。
内存映射数据文件的方法
1、 一个文件,一个缓存(缓存要足够大)
2、 一个文件,两个缓存(两个大小一致的缓存,顺序存放数据)
3、 两个文件,一个缓存(在新文件中操作,结束后删除源文件)
4、 一个文件,零个缓存(虚拟内存中操作,系统管理文件)
内存映射文件的使用
若要使用内存映射文件,必须执行下列操作步骤:
1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件。
//CreateFile()函数
HANDLE CreateFileW(
__in LPCWSTR lpFileName,//文件名
__in DWORD dwDesiredAccess,//访问方式
__in DWORD dwShareMode,//共享方式
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,//安全结构
__in DWORD dwCreationDisposition,//创建标志
__in DWORD dwFlagsAndAttributes,//
__in_opt HANDLE hTemplateFile//模板文件
);
2) 创建一个文件映射内核对象,告诉系统该文件的大小和你打算如何访问该文件。
//CreateFileMapping()函数
HANDLE CreateFileMappingW(
__in HANDLE hFile,//文件内核句柄
__in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//安全属性
__in DWORD flProtect, //保护属性
__in DWORD dwMaximumSizeHigh,//最大字节数,高32位
__in DWORD dwMaximumSizeLow,//低32位
__in_opt LPCWSTR lpName//文件映射对象名
);
3) 让系统将文件映射对象的全部或一部分映射到你的进程地址空间中。
//MapViewOfFile()//将文件数据映射到进程的地址空间
LPVOID MapViewOfFile(
__in HANDLE hFileMappingObject,//文件映射对象句柄
__in DWORD dwDesiredAccess,//访问属性
__in DWORD dwFileOffsetHigh,//第一个映射字节,高32位
__in DWORD dwFileOffsetLow,//低32位
__in SIZE_T dwNumberOfBytesToMap//映射的字节数量
);
当完成对内存映射文件的使用时,必须执行下面这些步骤将它清除:
1) 告诉系统从你的进程的地址空间中撤消文件映射内核对象的映像。
//Un MapViewOfFile()//
BOOL UnmapViewOfFile(
__in LPCVOID lpBaseAddress// MapViewOfFile的返回值,基地址
);
2) 关闭文件映射内核对象。
//CloseHandle()
3) 关闭文件内核对象。
//CloseHandle()
为了提高速度,系统将文件的数据页面进行高速缓存,并且在对文件的映射视图进行操作时不立即更新文件的磁盘映像。如果需要确保你的更新被写入磁盘,可以强制系统将修改过的数据的一部分或全部重新写入磁盘映像中,方法是调用FlushViewOfFile函数。
BOOL FlushViewOfFile(
__in LPCVOID lpBaseAddress,//基地址,以页为单位
__in SIZE_T dwNumberOfBytesToFlush//要刷新的字节数
);
内存映射文件的相关性
系统允许你映射一个文件的相同数据的多个视图。例如,你可以将文件开头的10KB映射到一个视图,然后将同一个文件的头4KB映射到另一个视图。只要你是映射相同的文件映射对象,系统就会确保映射的视图数据的相关性。例如,如果你的应用程序改变了一个视图中的文件内容,那么所有其他视图均被更新以反映这个变化。这是因为尽管页面多次被映射到进程的虚拟地址空间,但是系统只将数据放在单个RAM页面上。如果多个进程映射单个数据文件的视图,那么数据仍然是相关的,因为在数据文件中,每个RAM页面只有一个实例——正是这个RAM页面被映射到多个进程的地址空间。但是如果多个进程读写同一个文件,就会出现同步问题。
堆栈
对内存进行操作的第三个机制是使用堆栈。堆栈可以用来分配许多较小的数据块。例如,若要对链接表和链接树进行管理,最好的方法是使用堆栈,而不是虚拟内存操作方法或内存映射文件操作方法。堆栈的优点是,可以不考虑分配粒度和页面边界之类的问题,集中精力处理手头的任务。堆栈的缺点是,分配和释放内存块的速度比其他机制要慢,并且无法直接控制物理存储器的提交和回收。
当进程初始化时,系统在进程的地址空间中创建一个堆栈。该堆栈称为进程的默认堆栈。
按照默认设置,该堆栈的地址空间区域的大小是 1 MB。但是,系统可以扩大进程的默认堆栈,使它大于其默认值。
对默认堆栈的访问是顺序进行的。如果有多个线程只能顺序访问。默认堆栈是在进程开始执行之前创建的,并且在进程终止运行时自动被撤消。不能撤消进程的默认堆栈。每个堆栈均用它自己的堆栈句柄来标识,用于分配和释放堆栈中的内存块的所有堆栈函数都需要这个堆栈句柄作为其参数。除了进程的默认堆栈外,可以在进程的地址空间中创建一些辅助堆栈。
辅助堆栈的功能:保护组件、更加有效地进行内存管理、进行本地访问、减少线程同步的开销、迅速释放。
保护组件
将控制和数据分开保存。
更加有效地进行内存管理
在堆栈中分配相同大小的对象。
进行本地访问
可能将要同时访问的数据放在相互靠近的位置上。
减少线程同步的开销
这样的话,你必须自己控制线程的安全性。
迅速释放
将专用堆栈用于某些数据结构后,就可以释放整个堆栈,而不必显式释放堆栈中的每个内存块。
在进程中创建辅助堆栈
HANDLE WINAPI HeapCreate(
_In_ DWORD flOptions,//如何在堆栈上执行各种操作
_In_ SIZE_T dwInitialSize,// 最初提交给堆栈的字节数
_In_ SIZE_T dwMaximumSize//堆栈能够扩展到的最大值,为0时没有内存限制
);
参数一可以设定0、HEAP_NO_SERIALIZE、HEAP_GENERATE_EXCEPTIONS或者是这两个标志的组合。
若要从堆栈中分配内存块,只需要调用HeapAlloc函数:
LPVOID WINAPI HeapAlloc(
_In_ HANDLE hHeap,// 标识分配的内存块来自的堆栈的句柄
_In_ DWORD dwFlags,// 设定从堆栈中分配的内存块的字节数
_In_ SIZE_T dwBytes//设定影响分配的各个标志
);
参数三 支持的标志有3个:HEAP_ZERO_MEMORY、HEAP_GENERATE_EXCEPTIONS和HEAP_NO_SERIALIZE。
注意 :当你分配较大的内存块(大约1MB或者更大)时,最好使用VirtualAlloc函数,应该避免使用堆栈函数。
当从堆栈分配内存块时,需要一个请求过程:
1) 遍历分配的和释放的内存块的链接表。
2) 寻找一个空闲内存块的地址。
3) 通过将空闲内存块标记为“已分配”分配新内存块。
4) 将新内存块添加给内存块链接表。
当内存块增大或者减少时可以使用函数HeapReAlloc()函数改变内存块的容量
LPVOID WINAPI HeapReAlloc(
_In_ HANDLE hHeap,// 标识分配的内存块来自的堆栈的句柄
_In_ DWORD dwFlags,// 设定改变内存块大小时HeapReAlloc函数应该使用的标志
_In_ LPVOID lpMem,// 要改变其大小的内存块的地址
_In_ SIZE_T dwBytes//内存块的新的大小
);
参数二 可以使用的标志只有下面4个,即HEAP_GENERATE_EXCEPTIONS、HEAP_NO_SERIALIZE、HEAP_ZERO_MEMORY(扩大内存是填充0)和HEAP_REALLOC_IN_PLACE_ONLY(改变时不移动堆栈的内存块)
当内存块分配后,可以调用HeapSize函数来检索内存块的实际大小:
SIZE_T WINAPI HeapSize(
_In_ HANDLE hHeap,//标识堆栈
_In_ DWORD dwFlags,//这里只能是0或者HEAP_NO_SERIALIZE
_In_ LPCVOID lpMem//内存块的地址
);
当不再需要内存块时,可以调用HeapFree函数将它释放:
BOOL WINAPI HeapFree(
_In_ HANDLE hHeap,//标识堆栈
_In_ DWORD dwFlags,// 这里只能是0或者HEAP_NO_SERIALIZE
_In_ LPVOID lpMem//内存块的地址
);
如果应用程序不再需要它创建的堆栈,可以通过调用HeapDestroy函数将它撤消:
BOOL WINAPI HeapDestroy(
_In_ HANDLE hHeap//标识堆栈
);
如何在C++中使用堆栈
在C++中,调用new操作符,而不是调用通常的C运行期例程malloc,就可以执行类对象的分配操作。然后,当我们不再需要这个类对象时,调用delete操作符,而不是调用通常的C运行期例程free将它释放。
通过为我们的C + +类重载new和delete操作符,就能够很容易地利用堆栈函数。
其他和堆栈相关的函数
GetProcessHeaps函数来获取现有堆栈的句柄
HeapValidate函数用于验证堆栈的完整性
HeapCompact()合并地址中的空闲内存块并收回不包含已经分配的地址内存块的存储器页面
HeapLock和HeapUnlock 线程同步
HeapWalk() 用于调试目的
堆栈这里有点....
Windows核心编程小结3的更多相关文章
- Windows核心编程小结2
这一节看看内存管理相关的信息 首先看看虚拟内存 虚拟地址空间 32位系统 --- 4GB = 232 64 位系统 ---- 16EB = 264 虚拟内存表 当一个应用程序从硬盘加载到RAM时, ...
- Windows核心编程小结1
这本书绝对经典,看看定会增加不少知识.当然这本书有很多东西比<Windows程序设计第五版>中的更加详细. 1.Unicode:宽字节字符集 这是一个国际的字符标准,16位,最大可支持65 ...
- windows核心编程 - 线程同步机制
线程同步机制 常用的线程同步机制有很多种,主要分为用户模式和内核对象两类:其中 用户模式包括:原子操作.关键代码段 内核对象包括:时间内核对象(Event).等待定时器内核对象(WaitableTim ...
- windows核心编程---第九章 同步设备IO与异步设备IO之同步IO
同步设备IO 所谓同步IO是指线程在发起IO请求后会被挂起,IO完成后继续执行. 异步IO是指:线程发起IO请求后并不会挂起而是继续执行.IO完毕后会得到设备的通知.而IO完成端口就是实现这种通知的很 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- windows核心编程---第二章 字符和字符串处理
使用vc编程时项目-->属性-->常规栏下我们可以设置项目字符集合,它可以是ANSI(多字节)字符集,也可以是unicode字符集.一般情况下说Unicode都是指UTF-16.也 ...
- 回忆读windows 核心编程
看<windows 核心编程> 第五版到纤程了,下一章节即将介绍内存体系编程.如果做window平台下的开发,我感觉此书一定要读.记得开始讲解了window的基础,然后讲解内核对象.内核对 ...
- 《Windows核心编程》第5版 学习进度备忘
学习资源:<Windows核心编程>第5版 知识基础支持: 本书与<Windows程序设计>第5版珍藏版结合很好,二者重叠内容不多,二者互补性强,而且相关方面的优秀书籍 跳过的 ...
- 【windows核心编程】 第八章 用户模式下的线程同步
Windows核心编程 第八章 用户模式下的线程同步 1. 线程之间通信发生在以下两种情况: ① 需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性 ② 一个线程需要通知其他线程 ...
随机推荐
- 【Java/Android性能优 7】Android公共库——图片缓存 网络缓存 下拉及底部更多ListView 公共类
本文转自:http://www.trinea.cn/android/android-common-lib/ 介绍总结的一些android公共库,包含缓存(图片缓存.预取缓存.网络缓存).公共View( ...
- HDU 1712 ACboy needs your help AC男需要你的帮助 (分组的背包)
分组背包问题:有N件物品和一个容量为V的背包.第i件物品的体积是c[i],价值是w[i].这些物品被划分为若干组,每组中的物品互相冲突,最多选一件.求解将哪些物品装入背包可使这些物品的体积总和不超过背 ...
- COGS 898. [咲 -Saki-] 天才麻将少女什么编
★☆ 输入文件:sakinani.in 输出文件:sakinani.out 简单对比时间限制:1 s 内存限制:256 MB 题目背景 二十一世纪,世界上的麻将竞技人数超过一亿,日本每 ...
- 从.net到java,从基础架构到解决方案。
这一年,职业生涯中的最大变化,是从.net到java的直接跨越,是从平台架构到解决方案的不断完善. 砥砺前行 初出茅庐,天下无敌.再学三年,寸步难行.很多时候不是别人太强,真的是自己太弱,却不自知. ...
- 「C基础」C运算符的优先级
一.运算符的优先级表 C 语言的符号众多,由这些符号又组合成了各种各样的运算符.既然是运算符就一定有其特定的优先级,下表就是C 语言运算符的优先级表: 注:同一优先级的运算符,运算次序由结合方向所决定 ...
- Ubuntu中文乱码问题
版本 Ubuntu 14.1 系统安装完成后,中文都显示成了乱码 终端或者命令行里输入 sudo apt-get install zhcon 等安装完即可~ 运行的时候记得要加载vgz驱动和utf8支 ...
- 【BZOJ3925】[ZJOI2015] 地震后的幻想乡(状压期望DP)
点此看题面 大致题意: 有\(n\)个点和\(m\)条边,每条边的权值是一个\(0\sim1\)的随机实数,要你用\(n-1\)条边将图联通,问这\(n-1\)条边中边权最大值的期望最小值. 提示 这 ...
- 【洛谷4657】[CEOI2017] Chase(一个玄学的树形DP)
点此看题面 大致题意: 有一棵树,树上编号为\(i\)的节点上有\(F_i\)个铁球,逃亡者有\(V\)个磁铁,当他在某个节点放下磁铁时,与这个节点相邻的所有节点上的铁球都会被吸引到这个节点.然后一个 ...
- IIS6.0开启gzip压缩
双击IIS服务器,右键点击网站,点击属性,然后点击服务,我们看到HTTP压缩,然后在压缩应用程序文件,压缩静态文件中打钩,然后点击确定,第一步就完成了 然后我们右键点击web服务扩展,点击添加一个 ...
- 第九章 利用DOM脚本检索,替换,设置,追加样式信息
我们浏览器里看到的网页是由以下三层信息构成的一个共同体: -结构层,由HTML或XHTML之类的标记语言负责去搭建文档的结构. -表示层,由CSS负责设置文档的呈现效果. -行为层,由JavaScri ...