惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
阮一峰的网络日志
阮一峰的网络日志
云风的 BLOG
云风的 BLOG
D
Docker
Vercel News
Vercel News
IT之家
IT之家
Recent Announcements
Recent Announcements
Last Week in AI
Last Week in AI
V
Visual Studio Blog
Engineering at Meta
Engineering at Meta
腾讯CDC
Google DeepMind News
Google DeepMind News
I
InfoQ
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
The GitHub Blog
The GitHub Blog
博客园 - Franky
The Cloudflare Blog
A
About on SuperTechFans
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
T
Tenable Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Security Latest
Security Latest
H
Hackread – Cybersecurity News, Data Breaches, AI and More
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 聂微东
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Google Online Security Blog
Google Online Security Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Simon Willison's Weblog
Simon Willison's Weblog
The Last Watchdog
The Last Watchdog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
U
Unit 42
The Hacker News
The Hacker News
Martin Fowler
Martin Fowler
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
F
Full Disclosure
M
MIT News - Artificial intelligence
人人都是产品经理
人人都是产品经理
Hugging Face - Blog
Hugging Face - Blog
V
V2EX
Project Zero
Project Zero

博客园 - 悠然小调

nothing.... Ogre中在SceneNode节点旁显示二维字的代码 博文阅读密码验证 - 博客园 最简单的智能指针原理 模板的特化 计算基类虚表指针在派生类中的偏移量 写一个内存拷贝函数 [转]来自 COM 经验的八个教训 COM本质论学习笔记(一)IDL winsock中select的作用 windows核心编程学习笔记(三)线程池(Thread Pooling) windows核心编程学习笔记(八)结构化异常处理(Structured Exception Handling) [转]亲密接触VC6.0编译器 windows核心编程学习笔记(七)DLL Injection and API Hooking windows核心编程学习笔记(五.续)堆 windows核心编程学习笔记(四)windows内存结构/虚拟内存/线程的堆栈 windows核心编程学习笔记(二)Wait For Kernel Object(s) windows核心编程学习笔记(一)使用Critical Section [转]筛选法求素数
windows核心编程学习笔记(五)内存映射文件
悠然小调 · 2008-03-02 · via 博客园 - 悠然小调

    内存映射文件可以大大减少操作文件的开销,让程序运行更顺利,使不同进程共享数据变得更容易.
一.执行程序 
    当创建一个线程时,
    1.系统只是保留了足够大的对应的.exe文件区域,将.exe文件本身作为物理内存,执行映射,却并未提交;
    2.访问.exe文件的部分区域,以确定依赖的.dll(这将导致部分页面被提交);
    3.依次LoadLirary(像为.exe保留区域一样,也为.dll保留区域,并有些类似第4步);
    4.执行.exe的启动代码,并持续执行(执行到哪就提交哪块).

二.程序运行时修改全局变量或自修改代码
    同一个程序可能运行多个实例,而每个进程都把原始文件当作物理内存看待,那么其中一个进程修改了某部分数据或代码,其他进程是否也被改动了呢?答案是否定的。由于Copy-On-Write的干预,每当一个进程试图修改全局变量(或代码)时,都会把这个变量所在的页重新拷贝一份,并把虚拟地址映射到这个拷贝上,此时怎么改都只是改动单独为此进程准备的副本,而不会影响其他进程。

三.同一程序多个实例的数据共享
    是不是同一程序的多个实例就没办法共享数据了呢,有时这是很有用的!答案是可以共享,通过共享数据段可以很容易的在同一程序的多个实例之间共享数据。
    其实.exe或.dll文件分为若干个节(section),例如.text节通常存放程序的代码,.data节存放已初始化的全局变量等等,每个节也都有自己的属性:READ、WRITE、EXECUTE、SHARED。我们可以自己创建一个节,并指定SHARED属性(当然通常还要有READ、WRITE属性,否则没有什么意义了),这样,编译程序时就会自动生成该节,包含在该节中的内容将被该程序的多个进程所共享。
    示例代码如下:

    #pragma data_seg(".shared")
    unsigned 
int g_uRef = 0;   // 必须是初始化的,否则放到.shared之外
    #pragma data_seg()

    
#pragma comment(linker, "/SECTION:.shared,RWS")

     __declspec(allocate(
".shared")) int g_nforce; // 强制把 nforce 放入 .shared节中,无论它是否被初始化,很暴力哦

    这样一个共享的节就创建好了,程序可以像使用普通的全局变量一个样使用它~

int main()
{
    InterlockedExchangeAdd((PLONG) 
&g_uRef, 1);
    
    
/* do something */
    
    InterlockedExchangeAdd((PLONG) 
&g_uRef, -1);
    
    
return 0;
}

四.使用内存映射文件
    如果你需要想使用自己的变量一样来操作文件而不必事先把文件的全部或部分读取到特地分配的缓冲里,那么应该使用内存映射文件。
    1.用CreateFile来打开指定的文件,如果打开成功将返回文件的句柄(HANDLE),否则返回INVALID_HANDLE_VALUE;
    2.调用CreateFileMapping以创建文件映射对象,并传递上一步获得的HANDLE,将返回文件映射对象的句柄,失败的话返回NULL;
    3.调用MapViewOfFile(Ex),并传递上一步获得的文件映射对象,当然还要指定从文件的多少字节偏移处开始映射,以及要映射的大小——从Start到Start+Size构成了一个View,当然可以传递Size为0,那么将一直映射到文件结尾,如果映射成功,将返回可操作的地址,就像一个变量一样,随便怎么弄;
    4.使用这个地址,进行读写操作。通常不需要调用FlushViewOfFile来强制把修改写入到磁盘上的文件里,因为下一步的UnmapViewOfFile会把所有改动写入磁盘上的文件里的;
    5.当一切都搞定后,可以调用UnmapViewOfFile来取消映射,这回释放所有保留区域。如果在MapViewOfFile时传递了FILE_MAP_COPY,那么此步骤将放弃所有的修改,原文件将一点都不变化,否则,将写入改动后的数据;
    6.像关闭其他内核对象一样,调用CloseHandle依次关闭文件映射对象和文件对象,操作流程结束.

    书中给出了示例操作流程:

HANDLE hFile = CreateFile();
HANDLE hFileMapping 
= CreateFileMapping(hFile, );
CloseHandle(hFile);
PVOID pvFile 
= MapViewOfFile(hFileMapping, );
CloseHandle(hFileMapping);
// Use the memory-mapped file.

UnmapViewOfFile(pvFile);

许你想在不同的进程中简单的共享数据而不需要创建或打开什么磁盘上的文件,那么同样可以用内存映射文件——并且是最好的方法。此操作无需CreateFile了,直接调用CreateFileMapping并且给第一个参数传递INVALID_HANDLE_VALUE,并且传递一个独一无二的名字,其余的步骤类似,这样就建立了一个共享的数据。在另一个进程中,只需要同样的调用CreateFileMapping或OpenFileMapping,然后映射,那么就可以获得相同的共享数据,是不是很方便呢~
   
如果在调用CreateFileMapping时传递SEC_RESERVE,然后调用MapViewOfFile,那么获得的只是一个地址,却不能访问,因为还没提交。如果想使用,需要调用VirtualAlloc并传递MEM_COMMIT——这和操作由VirtualAlloc的MEM_RESERVE一样。