首页 > 其他 > 详细

第17章 内存映射文件(2)_内存映射文件的3个主要用途

时间:2015-10-31 22:53:44      阅读:308      评论:0      收藏:0      [点我收藏+]

17.4 映射到内存的可执行文件和DLL

(1)EXE文件格式

节名

作用

.text

.exe和.dll文件的代码

.data

己经初始化的数据

.bss

未初始化的数据

.reloc

重定位表(装载进程的进程地址空间)

.rdata

运行期只读数据

.CRT

C运行期只读数据

.debug

调用试信

.xdata

异常处理表

.tls

线程本地化存储

.idata

输入文件名表

.edata

输出文件名表

.rsrc

资源表

.didata

延迟输入文件名表

(2)加载exe的过程

  ①先CreateProcess创建进程内核对象,为进程创建一个私有地址空间(页目录和页表)

  ②系统根据exe大小,在默认的基地址0x0040 0000上预订适当大小的区域(可以在链接程序时用/BASE 选项更改基地址,方法是在VC工程属性\链接器\高级上设置)。

  ③系统会对地址空间区域进行标注,表明该区域的后备物理存储器来自于磁盘上的exe文件,而并非来自系统的页交换文件。

  ④读取exe文件的.idata节,此节列出exe所用到的所有dll文件。然后和exe文件一样,将dll文件映射到进程空间中。如果无法映射到基地址,系统会重新定位。(详见后面的《加载Dll过程》

  ⑤ 把所有的exe文件和DLL文件都映射到进程的地址空间之后,系统开始执行exe文件的启动代码,将第一页代码加载到内存,然后更新页目和页表。将第一条指令的地址交给线程指令指针。当系统执行时,会发现代码没有在内存中,就会通过页面错误机制,将exe文件中的代码加载到内存中。

(2)加载DLL的过程

  系统通过LoadLibrary载入每个DLL,如果哪个DLL需要调用其他DLL,系统会同样地调用LoadLibrary来载入相应的DLL,其载入过程如下:

  ①预订一块足够大的地址空间来容纳DLL,并在默认的基地址(如0x10000000)预订该区域。(可以使用/BASE链接器开关来指定这个基地址)。与Windows系统的DLL都有不同的基地址,这样即使把它们载入到同一个地址空间,也不会发生重叠。

  ②如果系统无法在DLL文件指定的基地址处预订区域(可能是该区域被另一个DLL或EXE占用,或区域不够大),这时系统尝试在另一个地址来为DLL预订区域。但这时需要重定位,但重定位需要占用页交换文件中额外的存储空间,而且会增加加载DLL所需的时间。而如果DLL不包含重定位信息(使用链接器的/FIXED开关构建的DLL是不包含重定位信息的,这开关的好处是可以使DLL文件变得更小),那么将无法被载入。

  ③系统会对地址空间区域进行标注表明该区域的后备物理存储器来自磁盘上的DLL文件,而不是系统的页交换文件。如果由于Windows不能将DLL载入到指定的基地址而必须执行重定位的话,那么系统还会另外进行标注,表明DLL中有一部分物理存储器被映射到了页交换文件。

(3)第2次加载exe的过程

  ①建立进程、映射进程空间与第1次加载EXE是一样的,只是当系统发现这个EXE己经建立了内存映射文件对象时,它就直接映射到进程空间了。只是当系统分配物理页面时,根据节的保护属性赋予页面的保护属性,对于代码节赋予READ属性,全局变量节赋予COPY_ON_WRITE属性。

  ②不同的实例共享代码节和其他的节,当实例需要改变页面内容时,会拷贝页面内容到新的页面,更新页目和页表。

  ③对于不同进程实例需要共享的变量,EXE文件有一个默认的节,给这个节赋予SHARED属性,我们也可以创建自己的SHARED节(请后面相关的内容)

17.4.1 同一个可执行文件和DLL的多个实例不会共享静态数据

(1)多实例的启动

  ①如果一个应用程序己经运行,当创建该应用程序的新实例时,会根据己经创建的同一个映射文件,打开另一个内存映射视图。通过内存映射文件,同一个实例可以共享内存中的代码和数据。

  ②当第2个实例启动时,系统把包含应用程序代码和数据的虚拟内存页面映射到第2个实例的地址空间。(注意虚拟内存即为内存的一部分,被载入到虚拟内存中的数据或代码可理解为就是内存中的数据了,注意与进程的地址空间的区别

(2)“写时复制”机制——保证了多实例不会共享静态数据

技术分享 

  ①任何时候,当应用程序试图写入内存映射文件的时候,系统会截获这种尝试,接着发生“写时复制”,即为应用程序(如实例2)分配一块新的内存,然后复制“数据页面2”的内容到新的页面。并重新将“实例2”地址空间中的“数据页面2”重新映射到“新页面”

  ②这样,“实例1”和“实例2”地址空间中的“数据页面2”就分别被映射到虚拟内存中的不同页面,从而保护数据,使得数据不会被另一个实例修改。

17.4.2 在同一个可执行文件或DLL的多个实例间共享静态数据

(1)可执行文件的常用段以及段的属性

  ①常用的段:如.bss、.data、.text等,详细见前面的EXE文件格式”表格

  ②段的属性

属性

含义

READ

可以从该段读取数据

WRITE

可以向该段写入数据

EXECUTE

可以执行该段的内容

SHARED

该段的内容为多个实例所共享(本质上是关闭了写时复制机制)

(2)多实例共享数据的方法

  ①创建自己的“数据段”

#pragma data_seg(“MyShareName”)  // MyShareName为段的名字,可自定义

LONG g_lInstanceCount = 0;   //要共享的变量必须是经过初始化的

#pragma data_seg(); //告诉编译器停止把己初始化的变量放到MyShareName段中。

② 将自定义的“数据段”属性设为“共享”

 #pragma comment(linker, “/SECTION:MyShareName,RWS”) //读、写、共享

(3)allocate声明符——可将初始化或未初始化的数据放到指定的段中

//创建一个“共享段”,并将己初始化的数据放入其中
#pragma data_seg("Shared") 
int a = 0; //己初始化数据,在“Shared”中
int b = 0; //未初始化的数据,不在“Shared”段中
#pragma  data_seg() //让编译器停止将己初始化变量放入“Shared”段

//初始化,并将变量放入“Shared”段中
__declspec(allocate("Shared")) int  c = 0;

//将未始化变量放入“Shared”段中
__declspec(allocate("Shared")) int  d;

//己初始化,但不在“Shared”段中
int e = 0;

//未初始化,也不在“Shared”段中
int f;  

【AppInst程序】统计共有多少个应用程序的实例正在运行

 技术分享

//AppInst.cpp

/************************************************************************
Module: AppInst.cpp
Notices:Copyright(c) 2008 Jeffrey Richter & Christophe Nasarre
************************************************************************/

#include "../../CommonFiles/CmnHdr.h"
#include "resource.h"
#include <tchar.h>

//////////////////////////////////////////////////////////////////////////
//系统广播消息
UINT g_uMsgAppInstCountUpdate = WM_APP + 123;

//////////////////////////////////////////////////////////////////////////
//创建“共享段”
#pragma data_seg("Shared")
volatile LONG g_lApplicationInstances = 0; //正在运行的实例的个数
#pragma data_seg()

//告诉编译器,让Shared段只有可读、可读及共享属性
#pragma comment(linker,"/Section:Shared,RWS")


BOOL Dlg_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam){
    chSETDLGICONS(hwnd, IDI_APPINST);

    //强制刷新,以显示正确的实例数。
    PostMessage(HWND_BROADCAST, g_uMsgAppInstCountUpdate, 0, 0);
    return TRUE;
}

//////////////////////////////////////////////////////////////////////////
void Dlg_OnCommand(HWND hWnd, int id, HWND hWndCtrl, UINT codeNotify){
    switch (id)
    {
    case IDCANCEL:
        EndDialog(hWnd, id);
        break;
    }
}

//////////////////////////////////////////////////////////////////////////
INT_PTR WINAPI Dlg_Proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){

    if (uMsg == g_uMsgAppInstCountUpdate){
        SetDlgItemInt(hwnd, IDC_COUNT, g_lApplicationInstances, FALSE);
    }

    switch (uMsg)
    {
        chHANDLE_DLGMSG(hwnd, WM_INITDIALOG, Dlg_OnInitDialog);
        chHANDLE_DLGMSG(hwnd, WM_COMMAND, Dlg_OnCommand);
    }
    return FALSE;
}

//////////////////////////////////////////////////////////////////////////
int WINAPI _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nShowCmd)
{
    //注删用于广播的消息,并何存ID,该消息用来通知实例个数发生变化
    g_uMsgAppInstCountUpdate = RegisterWindowMessage(TEXT("MsgAppInstCountUpdate"));

    //新的应用程序实例正在运行
    InterlockedExchangeAdd(&g_lApplicationInstances, 1);

    DialogBox(hInstance, MAKEINTRESOURCE(IDD_APPINST), NULL, Dlg_Proc);

    //应用程序的结束运行
    InterlockedExchangeAdd(&g_lApplicationInstances, -1);

    //通知其他实例更新显示
    PostMessage(HWND_BROADCAST, g_uMsgAppInstCountUpdate, 0, 0);

    return 0;
}

//resource.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 17_AppInst.rc 使用
//
#define IDD_APPINST                     1
#define IDC_COUNT                       100
#define IDI_APPINST                     101
#define IDI_ICON1                       102

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1001
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

//AppInst.rc

// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_APPINST DIALOGEX 0, 0, 161, 21
STYLE DS_SETFONT | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "多个实例的应用程序"
FONT 10, "宋体", 400, 0, 0x0
BEGIN
    LTEXT           "正在运行的实例数:",IDC_STATIC,25,6,93,8,SS_NOPREFIX
    RTEXT           "#",IDC_COUNT,113,6,16,12,SS_NOPREFIX
END


/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_APPINST             ICON                    "AppInst.Ico"

/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    IDD_APPINST, DIALOG
    BEGIN
    END
END
#endif    // APSTUDIO_INVOKED

#endif    // 中文(简体,中国) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

 

第17章 内存映射文件(2)_内存映射文件的3个主要用途

原文:http://www.cnblogs.com/5iedu/p/4926309.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!