Win 内存映射和堆栈

时间:2023-01-06 17:40:13

内存映射和堆栈

内存映射文件

内存映射文件可以用于3个不同的目的:

  系统使用内存映射文件,以便加载和执行.exe和DLL文件。这可以大大节省页文件空间和应用程序启动运行所需的时间。

  可以使用内存映射文件来访问磁盘上的数据文件。这使你可以不必对文件执行I/O操作,并且可以不必对文件内容进行缓存。

  可以使用内存映射文件,使同一台计算机上运行的多个进程能够相互之间共享数据。Windows确实提供了其他一些方法,以便在进程之间进行数据通信,但是这些方法都是使用内存映射文件来实现的,这使得内存映射文件成为单个计算机上的多个进程互相进行通信的最有效的方法。

内存映射数据文件的方法

  1、 一个文件,一个缓存(缓存要足够大)

  2、 一个文件,两个缓存(两个大小一致的缓存,顺序存放数据)

  3、 两个文件,一个缓存(在新文件中操作,结束后删除源文件)

  4、 一个文件,零个缓存(虚拟内存中操作,系统管理文件)

内存映射文件的使用

若要使用内存映射文件,必须执行下列操作步骤:

1) 创建或打开一个文件内核对象,该对象用于标识磁盘上你想用作内存映射文件的文件。

Win 内存映射和堆栈
 1 //CreateFile()函数
2 HANDLE CreateFileW(
3 __in LPCWSTR lpFileName,//文件名
4 __in DWORD dwDesiredAccess,//访问方式
5 __in DWORD dwShareMode,//共享方式
6 __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,//安全结构
7 __in DWORD dwCreationDisposition,//创建标志
8 __in DWORD dwFlagsAndAttributes,//
9 __in_opt HANDLE hTemplateFile//模板文件
10 );
Win 内存映射和堆栈

2) 创建一个文件映射内核对象,告诉系统该文件的大小和你打算如何访问该文件。

Win 内存映射和堆栈
1 //CreateFileMapping()函数
2 HANDLE CreateFileMappingW(
3 __in HANDLE hFile,//文件内核句柄
4 __in_opt LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//安全属性
5 __in DWORD flProtect, //保护属性
6 __in DWORD dwMaximumSizeHigh,//最大字节数,高32位
7 __in DWORD dwMaximumSizeLow,//低32位
8 __in_opt LPCWSTR lpName//文件映射对象名
9 );
Win 内存映射和堆栈

3) 让系统将文件映射对象的全部或一部分映射到你的进程地址空间中。

Win 内存映射和堆栈
1 //MapViewOfFile()//将文件数据映射到进程的地址空间
2 LPVOID MapViewOfFile(
3 __in HANDLE hFileMappingObject,//文件映射对象句柄
4 __in DWORD dwDesiredAccess,//访问属性
5 __in DWORD dwFileOffsetHigh,//第一个映射字节,高32位
6 __in DWORD dwFileOffsetLow,//低32位
7 __in SIZE_T dwNumberOfBytesToMap//映射的字节数量
8 );
Win 内存映射和堆栈

当完成对内存映射文件的使用时,必须执行下面这些步骤将它清除:

1) 告诉系统从你的进程的地址空间中撤消文件映射内核对象的映像。

1 //Un MapViewOfFile()//
2 BOOL UnmapViewOfFile(
3 __in LPCVOID lpBaseAddress// MapViewOfFile的返回值,基地址
4 );

2) 关闭文件映射内核对象。

//CloseHandle()

3) 关闭文件内核对象。

//CloseHandle()

  为了提高速度,系统将文件的数据页面进行高速缓存,并且在对文件的映射视图进行操作时不立即更新文件的磁盘映像。如果需要确保你的更新被写入磁盘,可以强制系统将修改过的数据的一部分或全部重新写入磁盘映像中,方法是调用FlushViewOfFile函数。

1 BOOL FlushViewOfFile(
2 __in LPCVOID lpBaseAddress,//基地址,以页为单位
3 __in SIZE_T dwNumberOfBytesToFlush//要刷新的字节数
4 );

内存映射文件的相关性

  系统允许你映射一个文件的相同数据的多个视图。例如,你可以将文件开头的10KB映射到一个视图,然后将同一个文件的头4KB映射到另一个视图。只要你是映射相同的文件映射对象,系统就会确保映射的视图数据的相关性。例如,如果你的应用程序改变了一个视图中的文件内容,那么所有其他视图均被更新以反映这个变化。这是因为尽管页面多次被映射到进程的虚拟地址空间,但是系统只将数据放在单个RAM页面上。如果多个进程映射单个数据文件的视图,那么数据仍然是相关的,因为在数据文件中,每个RAM页面只有一个实例——正是这个RAM页面被映射到多个进程的地址空间。但是如果多个进程读写同一个文件,就会出现同步问题。

堆栈

  对内存进行操作的第三个机制是使用堆栈。堆栈可以用来分配许多较小的数据块。例如,若要对链接表和链接树进行管理,最好的方法是使用堆栈,而不是虚拟内存操作方法或内存映射文件操作方法。堆栈的优点是,可以不考虑分配粒度和页面边界之类的问题,集中精力处理手头的任务。堆栈的缺点是,分配和释放内存块的速度比其他机制要慢,并且无法直接控制物理存储器的提交和回收。

  当进程初始化时,系统在进程的地址空间中创建一个堆栈。该堆栈称为进程的默认堆栈。

  按照默认设置,该堆栈的地址空间区域的大小是 1 MB。但是,系统可以扩大进程的默认堆栈,使它大于其默认值。

  对默认堆栈的访问是顺序进行的。如果有多个线程只能顺序访问。默认堆栈是在进程开始执行之前创建的,并且在进程终止运行时自动被撤消。不能撤消进程的默认堆栈。每个堆栈均用它自己的堆栈句柄来标识,用于分配和释放堆栈中的内存块的所有堆栈函数都需要这个堆栈句柄作为其参数。除了进程的默认堆栈外,可以在进程的地址空间中创建一些辅助堆栈

  辅助堆栈的功能:保护组件、更加有效地进行内存管理、进行本地访问、减少线程同步的开销、迅速释放。

  保护组件

    将控制和数据分开保存。

  更加有效地进行内存管理

    在堆栈中分配相同大小的对象。

  进行本地访问

    可能将要同时访问的数据放在相互靠近的位置上。

  减少线程同步的开销

  这样的话,你必须自己控制线程的安全性。

  迅速释放

  将专用堆栈用于某些数据结构后,就可以释放整个堆栈,而不必显式释放堆栈中的每个内存块。

在进程中创建辅助堆栈
1 HANDLE WINAPI HeapCreate(
2 _In_ DWORD flOptions,//如何在堆栈上执行各种操作
3 _In_ SIZE_T dwInitialSize,// 最初提交给堆栈的字节数
4 _In_ SIZE_T dwMaximumSize//堆栈能够扩展到的最大值,为0时没有内存限制
5 );

  参数一可以设定0、HEAP_NO_SERIALIZE、HEAP_GENERATE_EXCEPTIONS或者是这两个标志的组合。

若要从堆栈中分配内存块,只需要调用HeapAlloc函数:

1 LPVOID WINAPI HeapAlloc(
2 _In_ HANDLE hHeap,// 标识分配的内存块来自的堆栈的句柄
3 _In_ DWORD dwFlags,// 设定从堆栈中分配的内存块的字节数
4 _In_ SIZE_T dwBytes//设定影响分配的各个标志
5 );

  参数三 支持的标志有3个:HEAP_ZERO_MEMORY、HEAP_GENERATE_EXCEPTIONS和HEAP_NO_SERIALIZE。

注意 :当你分配较大的内存块(大约1MB或者更大)时,最好使用VirtualAlloc函数,应该避免使用堆栈函数。

当从堆栈分配内存块时,需要一个请求过程:

  1) 遍历分配的和释放的内存块的链接表。

  2) 寻找一个空闲内存块的地址。

  3) 通过将空闲内存块标记为“已分配”分配新内存块。

  4) 将新内存块添加给内存块链接表。

当内存块增大或者减少时可以使用函数HeapReAlloc()函数改变内存块的容量

1 LPVOID WINAPI HeapReAlloc(
2 _In_ HANDLE hHeap,// 标识分配的内存块来自的堆栈的句柄
3 _In_ DWORD dwFlags,// 设定改变内存块大小时HeapReAlloc函数应该使用的标志
4 _In_ LPVOID lpMem,// 要改变其大小的内存块的地址
5 _In_ SIZE_T dwBytes//内存块的新的大小
6 );

  参数二  可以使用的标志只有下面4个,即HEAP_GENERATE_EXCEPTIONS、HEAP_NO_SERIALIZE、HEAP_ZERO_MEMORY(扩大内存是填充0)和HEAP_REALLOC_IN_PLACE_ONLY(改变时不移动堆栈的内存块)

当内存块分配后,可以调用HeapSize函数来检索内存块的实际大小:

1 SIZE_T WINAPI HeapSize(
2 _In_ HANDLE hHeap,//标识堆栈
3 _In_ DWORD dwFlags,//这里只能是0或者HEAP_NO_SERIALIZE
4 _In_ LPCVOID lpMem//内存块的地址
5 );

当不再需要内存块时,可以调用HeapFree函数将它释放:

1 BOOL WINAPI HeapFree(
2 _In_ HANDLE hHeap,//标识堆栈
3 _In_ DWORD dwFlags,// 这里只能是0或者HEAP_NO_SERIALIZE
4 _In_ LPVOID lpMem//内存块的地址
5 );
如果应用程序不再需要它创建的堆栈,可以通过调用HeapDestroy函数将它撤消:
BOOL WINAPI HeapDestroy(
_In_ HANDLE hHeap//标识堆栈
);
如何在C++中使用堆栈

  在C++中,调用new操作符,而不是调用通常的C运行期例程malloc,就可以执行类对象的分配操作。然后,当我们不再需要这个类对象时,调用delete操作符,而不是调用通常的C运行期例程free将它释放。

  通过为我们的C + +类重载new和delete操作符,就能够很容易地利用堆栈函数。

  其他和堆栈相关的函数

  GetProcessHeaps函数来获取现有堆栈的句柄

  HeapValidate函数用于验证堆栈的完整性

  HeapCompact()合并地址中的空闲内存块并收回不包含已经分配的地址内存块的存储器页面

  HeapLock和HeapUnlock  线程同步

  HeapWalk() 用于调试目的


堆栈这里有点....

 
 
分类: C++Windows
标签: C++Windows

Win 内存映射和堆栈的更多相关文章

  1. JAVA NIO FileChannel 内存映射文件

      文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...

  2. 内存映射与DMA

    1.mmap系统调用的实现过程,该系统调用直接将设备内存映射到用户进程的地址空间. 2.用户空间内存如何映射到内核中(get_user_pages). 3.直接内存访问(DMA),他使得外设具有直接访 ...

  3. Win内存分配函数(GlobalAlloc/HeapAlloc/LocalAlloc/VirtualAlloc)

    Win内存分配函数(GlobalAlloc/HeapAlloc/LocalAlloc/VirtualAlloc) 来源:http://blog.csdn.net/chunyexiyu/article/ ...

  4. 《Linux Device Drivers》第十五章 内存映射和DMA——note

    简单介绍 很多类型的驱动程序编程都须要了解一些虚拟内存子系统怎样工作的知识 当遇到更为复杂.性能要求更为苛刻的子系统时,本章所讨论的内容迟早都要用到 本章的内容分成三个部分 讲述mmap系统调用的实现 ...

  5. 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件

    本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...

  6. LDD3 第15章 内存映射和DMA

    本章内容分为三个部分: 第一部分讲述了mmap系统调用的实现过程.将设备内存直接映射到用户进程的地址空间,尽管不是所有设备都需要,但是能显著的提高设备性能. 如何跨越边界直接访问用户空间的内存页,一些 ...

  7. 内存映射文件MemoryMappedFile使用

    参考资料: http://blog.csdn.net/bitfan/article/details/4438458 所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特 ...

  8. Python之mmap内存映射模块(大文本处理)说明

    背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力.关于sed的说明可以看了解sed的工作原理,本文将介绍通过 ...

  9. 使用ZwMapViewOfSection创建内存映射文件总结

    标 题: [原创]使用ZwMapViewOfSection创建内存映射文件总结 作 者: 小覃 时 间: 2012-06-15,02:28:36 链 接: http://bbs.pediy.com/s ...

随机推荐

  1. jQuery实现公告文字左右滚动

    jQuery实现公告文字左右滚动的代码. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &qu ...

  2. 写一段方便的SQL 循环查每一天的数据

    declare @recd int,@i int,@a int,@count int,@day1 date,@day2 date,@days int set @day1='2014-8-24' set ...

  3. 【爬虫问题】爬取tv&period;sohu&period;com的页面&comma; 提取视频相关信息

    尝试解决下面的问题 问题: 爬取tv.sohu.com的页面, 提取视频相关信息,不可用爬虫框架完成 何为视频i关信息?属性有哪些? 需求: 做到最大可能的页面覆盖率 *使用httpClient 模拟 ...

  4. &lbrack;UWP&rsqb;浅谈按钮设计

    一时兴起想谈谈UWP按钮的设计. 按钮是UI中最重要的元素之一,可能也是用得最多的交互元素.好的按钮设计可以有效提高用户体验,构造让人眼前一亮的UI.而且按钮通常不会影响布局,小小的按钮无论怎么改也不 ...

  5. Tomcat 下配置一个ip绑定多个域名

    原文:http://pkblog.blog.sohu.com/68921246.html 在网上找了半天也没找到相关的资料,都说的太含糊.本人对tomcat下配置 一ip对多域名的方法详细如下,按下面 ...

  6. linux内核中链表代码分析---list&period;h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

  7. 001&period; MyBatis&plus;SpringMVC&plus;Spring&lbrack;重置版&rsqb;

    说在前面的话 三阶段的课程知识点和细节很多,请假应该杜绝! 课后需抓紧时间复习,提高代码质量和速度! 课程周期和学习课程顺序为:[正常情况下] MyBatis 持久层框架 [2周] SpringMVC ...

  8. 分布式唯一ID的几种生成方案

    前言 在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID.退款ID等.那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们应该采用哪种适合自己的解决方案是十 ...

  9. Array&period;Copy 数据是克隆吗?

    偶然看到 Array.Copy 方法的时候,想到,它是否是克隆,又是否是深克隆. 做了一个测试 public class abc { public string hello; } [TestMetho ...

  10. 〖Linux〗zigbee实验之cc2430的cc debugger固件升级实录

    开发环境:Windows XP 1. (Trouble)一开始,使用IAR提示此设备不可使用(意味着无法下载程序): 2. (Search)通过一番的仔细查找,发现是cc debugger的Evalu ...