C++编译运行的子程序返回的数组指针能否被跨进程直接访问?
结论
直接访问编译生成的子程序输出的数组首地址,必然触发段错误,完全不具备可行性。
核心原因
- 所有现代操作系统都会对用户态进程做强制的虚拟地址空间隔离:每个进程持有的内存地址都是独立的虚拟地址,不是真实物理内存地址。你从子程序输出拿到的数组首地址,是子程序自身虚拟地址空间内的栈上地址,和父进程的虚拟地址空间没有任何映射关联。父进程直接访问这个地址,要么命中未分配的内存页触发段错误,要么读到自身地址空间内对应位置的无关垃圾值。
- 父子进程之间不存在内存访问特权:就算子程序是当前进程编译、拉起的,操作系统的进程隔离规则也不会有任何豁免。进程隔离是内核层面强制执行的安全机制,和进程的创建来源、运行权限无关,即便是root权限运行的父进程,也不能直接裸访问其他进程的私有内存。
- 示例代码中的数组是main函数栈帧上的局部变量,生命周期完全依附于子程序的main函数栈,就算是同一个进程内,只要main函数返回该地址就会成为野指针,跨进程场景下更不可能合法访问。
跨进程高性能消息传递的正确方案
不存在完全不借助系统API就能跨进程共享内存的实现。如果要实现零拷贝的高性能数组传递,正确方案是使用操作系统提供的共享内存机制:
- 父进程创建共享内存段,获取对应的内存句柄
- 启动子程序时将共享内存句柄传递给子程序
- 两个进程将同一块共享内存映射到各自的虚拟地址空间,之后就可以像访问进程内内存一样读写这块内存,没有额外拷贝开销,性能最高。
你当前的实现逻辑完全没有做共享内存映射,本质是两个完全独立的进程:
std::string code = R"( #include<thread> #include<iostream> int main() { int array[@@size@@]; std::cout<<(size_t)&array[0]<<std::endl; std::this_thread::sleep(1000000000); return 0; } )"; boost::replace_all(code, "@@size@@", std::to_string(memSize));
对应的编译命令也没有处理内存共享相关逻辑:
system("g++ code.cpp");
补充:如果不做共享内存映射,也可以通过系统提供的进程内存调试接口(比如Linux下的
process_vm_readv/process_vm_writev、ptrace接口)读写其他进程内存,但这类接口有额外的调用开销,性能远低于共享内存,也不属于“无API直接访问”的范畴。
内容的提问来源于stack exchange,提问作者huseyin tugrul buyukisik
相关产品推荐
相关产品推荐

