DLL只读内存疑问:多进程映射全局const字符串地址问题
你的预期完全符合Windows平台下DLL的内存加载机制,咱们一步步拆解细节:
字符串的存储位置
你在dll.cpp里写的const char *str = "qwerty123";,其中字符串字面量"qwerty123"会被编译器妥妥地放在DLL的只读数据段(一般是.rdata段)——毕竟它是不可修改的常量。而指针str本身作为全局const指针,在调试模式+无优化的设置下,也会被放在只读段里,不会乱挪位置。DLLEXPORT的作用
通过extern "C" {DLLEXPORT extern const char* str;}导出这个指针变量,本质是给A1.exe和A2.exe开了个“通道”,让它们能通过动态链接找到这个指针的地址。这里要注意:导出的是指针变量,不是字符串本身,但指针指向的正是DLL只读段里的那个"qwerty123"。Windows内存管理器的映射逻辑
当A1.exe加载这个DLL时,Windows会把DLL的只读段映射到A1虚拟地址空间的某块区域;等A2.exe加载同一个DLL时,内存管理器会把存储"qwerty123"的同一份物理内存页,映射到A2虚拟地址空间的另一个完全不同的虚拟地址上。这是因为只读段不会被修改,Windows可以让多个进程共享同一份物理内存,既省空间又高效——这就是只读段下“写时复制”(Copy-On-Write)机制的典型表现,只不过因为不会写,所以全程共享。调试模式+无优化的影响
你开了调试模式还关了优化,编译器就不会搞那些花里胡哨的操作——比如把字符串合并到主程序的内存里,或者重定向指针地址之类的。所以这个字符串肯定老老实实地待在DLL的只读段里,完全按照你预期的方式被映射到两个进程的不同虚拟地址上。
额外提一句:如果把const去掉,让字符串变成可修改的,那Windows会在某个进程第一次修改这个字符串时,给该进程复制一份专属的物理内存页,这时候A1和A2改的就是各自的副本了。但你的场景里是const字符串,所以全程共享同一份物理内存。
内容的提问来源于stack exchange,提问作者user7242858

