Windows中同一个EXE文件多次加载过程



Windows中EXE文件加载是基于内存映射文件的。

当EXE文件第一次被加载。

  • 首先系统会先创建一个进程内核对象,并创建一个新的进程地址空间。
  • 系统调用CreateFile打开对应的exe文件。
  • 根据PE文件的路径创建文件映射对象,调用CreateFileMapping的参数fdwProtect传入SEC_IMAGE表示映射的文件是一个PE文件,这样系统会按照PE文件头中指定的信息在进程空间指定的地址处预留指定大小的区域,接着调用MapViewOfFileEx将内存映射文件映射到指定的进程地址空间处,因为映射的是一个用SEC_IMAGE属性创建的PE文件的内存映射文件所以系统会根据PE文件头中的信息将PE文件的内存映射文件映射到进程地址空间的各个地址处,并指定此区域的物理存储器来自于磁盘上的EXE文件。
  • 这时PE文件并未真正加载到物理内存中,接着会根据PE文件中的输入表中的DLL信息加载DLL。
  • 同样会按照DLL文件头的信息在进程空间中指定的地址处预留指定大小的区域,但因为其涉及到重定位所以地址可以改变,且指定预留区域的物理存储器来自于磁盘上的DLL文件和页交换文件。
  • 当所有的DLL文件也都预留完区域后,会将EXE文件的第一张代码页加载到内存中,这时CPU运行程序。
  • 当CPU运行到内存中不存在的代码页时会发生缺页中断,中断处理程序会将对应的页从磁盘中的EXE文件或DLL文件中加载到内存中。

当EXE文件第二次被加载。

  • 因为其会判断此文件已经创建了文件映射对象,所以其不会再次创建文件映射对象了。
  • 其直接利用已创建的文件映射对象来调用接着调用MapViewOfFileEx创建新的映射(映射到自己的进程空间中),因为其与第一次运行的程序实例使用的是同一个文件映射对象,因此其与第一次运行的程序实际使用同一块物理内存。

不使用共享内存

因为同一个EXE的多个实例使用的是同一物理内存,当在一个实例的进程空间中更改全局变量或者是局部变量时其他进程也应会做出相应变化。但是实际并没有,也就是全局变量和静态变量并不能在同一个EXE的多个实例进程间共享。原因是因为存在写时复制机制,当尝试更改全局变量或者是静态变量时系统会将物理内存对应的内存页复制到页交换文件中,并修改页交换文件中的内容。此后进程对应的区域就会映射到页交换文件处而不是物理内存处。这样不同的进程映射到不同的页交换文件中所以其不会更改物理内存中的数据,同样无法实现进程间通讯。

使用共享内存

在EXE中使用

使用共享内存实际就是屏蔽写时复制机制,如果指定内存为共享内存则在不同的进程实例中对其更改时,其不会发生写时复制而是直接更改对应物理内存中的数据,所以可以实现进程间通讯。

#pragma data_seg("区块名")
DWORD dwData = 0;
#pragma data_seg()

在源程序中使用如上代码告诉编译器创建一个区块,并且在区块中定义一个变量,此变量必须初始化否则编译器不会将其放在此区块中而是放在其他区块中。

#pragma comment(linker, "/SECTION:区块名,RWS")

在源程序中使用如上代码告诉链接器,更改指定区块的属性,R表示读,W表示写,E表示执行,S表示共享。

在DLL中使用

因为如果一个DLL被多个EXE加载,那么其也只是对此DLL的文件映射对象多建立了几个映射,实际在物理内存中只会存在一块DLL的内存,所以我们可以通过在DLL中使用共享内存而在不同的进程中加载此DLL,利用此DLL的共享内存实现进程间通讯。

#pragma data_seg("区块名")
DWORD dwData = 0;
#pragma data_seg() #pragma comment(linker, "/SECTION:区块名,RWS") //导出函数
DWORD GetData()
{
return dwData;
} void SetData(DWORD dwNum)
{
dwData = dwNum;
}

在DLL中使用共享内存与在EXE中使用共享内存相似,因为DLL被其他进程加载不能直接访问到共享内存中的变量,所以通过对DLL导出函数实现对DLL共享内存的访问。

Windows进程间通讯(IPC)----共享内存的更多相关文章

  1. QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开     本文地址:h ...

  2. High Performance Networking in Google Chrome 进程间通讯(IPC) 多进程资源加载

    小结: 1. 小文件存储于一个文件中: 在内部,磁盘缓存(disk cache)实现了它自己的一组数据结构, 它们被存储在一个单独的缓存目录里.其中有索引文件(在浏览器启动时加载到内存中),数据文件( ...

  3. Android AIDL 进行进程间通讯(IPC)

    编写AIDL文件时,需要注意: 1.接口名和aidl文件名相同. 2.接口和方法前不用加访问权限修饰符 (public.private.protected等,也不能用final.static). 3. ...

  4. java 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)

    参考文章:http://ifeve.com/java-concurrency-thread-directory/ 其中的竞态,线程安全,内存模型,线程间的通信,java ThreadLocal类小节部 ...

  5. 【转】JAVA 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)

    原文地址:https://www.cnblogs.com/edenpans/p/6020113.html 参考文章:http://ifeve.com/java-concurrency-thread-d ...

  6. Windows进程间通讯(IPC)----内存映射文件

    内存映射文件原理 内存映射文件是通过在虚拟地址空间中预留一块区域,然后通过从磁盘中已存在的文件为其调度物理存储器,访问此虚拟内存空间就相当于访问此磁盘文件了. 内存映射文件实现过程 HANDLE hF ...

  7. Windows进程间通讯(IPC)----消息队列

    消息队列 windows系统是通过消息驱动的,每移动一下鼠标,点击一下屏幕都会产生一个消息.这些消息会先被放在windows的一个系统消息队列(先进先出)中,windows系统会为每一个GUI线程创建 ...

  8. Windows进程间通讯(IPC)----WM_COPYDATA

    WM_COPYDATA通讯思路 通过向其他进程的窗口过程发送WM_COPYDATA消息可以实现进程间通讯. 只能通过SendMessage发送WM_COPYDATA消息,而不能通过PostMessag ...

  9. 服务 远程服务 AIDL 进程间通讯 IPC

    Activity aidl接口文件 package com.bqt.aidlservice;  interface IBinderInterface {     /* 更改文件后缀为[.aidl]去掉 ...

随机推荐

  1. Java 树结构实际应用 三(二叉排序树)

    二叉排序树 1 先看一个需求 给你一个数列 (7, 3, 10, 12, 5, 1, 9),要求能够高效的完成对数据的查询和添加   2 解决方案分析  使用数组 数组未排序, 优点:直接在数组尾添 ...

  2. CUDA Cudnn pytorch 安装及错误 RuntimeError: cuDNN error: CUDNN_STATUS_NOT_INITIALIZED解决

    看我结论,大家试试看最后装pytorch看行不行,不行就去冲了PyTorch   /Doge ubuntu 20.04 下安装CUDA,参考这个博主写的,先看显卡支持的最高CUDA版本,之后找一个较新 ...

  3. 【面试技巧】老生常谈之 n 种使用 CSS 实现三角形的技巧

    在一些面经中,经常能看到有关 CSS 的题目都会有一道如何使用 CSS 绘制三角形,而常见的回答通常也只有使用 border 进行绘制一种方法. 而 CSS 发展到今天,其实有很多有意思的仅仅使用 C ...

  4. 2020 OO 第二单元总结

    只要跑得够快即使从头关到尾你也喜欢吗? 一.设计策略 1.1 总体策略概述 在多线程的协同和同步控制方面,我三次作业都是采用生产者/消费者模式(还憨憨地在内部分了customer.producer.t ...

  5. Android-SQLite的介绍 以及四个基本操作~

    在Android 开发中SQLite起着很重要的作用,网上SQLite的教程有很多很多,不过那些教程大多数都讲得不是很全面.本人总结了一些SQLite的常用的方法,借着论坛的大赛,跟大家分享分享的.一 ...

  6. MySQL数据库高级四:工具拾遗(视图)

    视图

  7. Druid 监控分布式解决方案

    什么是 Druid Monitor Druid 是一个非常强大的数据库连接池,但是它的强大并不仅仅体现在作为一个高性能连接池加快数据访问上和连接管理上,它内置了一个强大的监控工具:Druid Moni ...

  8. 「性能提升」扩展 Spring Cache 支持多级缓存

    为什么多级缓存 缓存的引入是现在大部分系统所必须考虑的 redis 作为常用中间件,虽然我们一般业务系统(毕竟业务量有限)不会遇到如下图 在随着 data-size 的增大和数据结构的复杂的造成性能下 ...

  9. Window、Ubuntu传输文件到阿里云服务器

    Ubuntu传输文件到阿里云服务器 scp -r file(ubuntu的文件) root(用户名)@xx.xx.xx.xx(公网ip):/home/(目标文件夹) Window传输文件到阿里云服务器 ...

  10. python工业互联网应用实战13—基于selenium的功能测试

    本章节我们再来说说测试,单元测试和功能测试.单元测试我们在数据验证章节简单提过了,本章我们进一步如何用单元测试来测试view的功能代码:同时,也涉及一下基于selenium的功能测试做法.笔者过去的项 ...