【问题标题】:Same memory address for different processes不同进程使用相同的内存地址
【发布时间】:2018-07-03 09:34:12
【问题描述】:

我只是不明白为什么这段代码会以它的方式工作(而不是我期望的):

 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/wait.h>
 #include <sys/types.h>

 int main()
 {
     int buffer;
     int* address;

     address=&buffer;


     if(fork()==0)
     {
         *address=27;
         printf("Address %ld stores %d\n",(long)address,*address);
         exit(0);
     }
     wait(NULL);

     printf("Address %ld stores %d\n",(long)(&buffer),buffer);    
     return 0;
 }

为什么即使指向同一个内存地址,系统也会存储不同的变量?

注意:我从没想过这段代码能正常工作,否则一大堆管道和东西就没有任何意义;我只是想了解这里发生了什么。

【问题讨论】:

  • 你的输出是什么,你期望什么?我希望buffer 有一个垃圾值,这就是我得到的:ideone.com/ESqx1I
  • 你必须熟悉物理和虚拟内存地址的区别
  • @mch 这也是我得到的,读起来感觉很奇怪:内存地址 X 存储 27,内存地址 X 存储 0(我的意思是,假设 X=X...)
  • @Ctx 看起来我正在考虑虚拟内存,就好像它是物理内存一样。有没有办法强制进程写入特定的物理地址?
  • @Guillermo.D.S.没有可移植的方式来写入特定的物理地址,但无论如何我都看不到这样做的充分理由。还有其他机制可以在进程之间共享内存,例如(线程、posix 共享内存等)。

标签: c memory-management shared-memory


【解决方案1】:

这并不是一个真正的 C 问题,而是关于(现代)操作系统的行为。

简而言之:现代操作系统上的用户空间程序在一些私有虚拟地址空间中运行。访问内存时,虚拟地址被转换为物理地址。实际内存和虚拟地址空间之间的映射是由操作系统设置的——内存被分成页,一个页可以“映射”到进程的地址空间中。

fork() 通常只是将相同的内存映射到它创建的第二个进程,但是一旦写入该内存,就会复制页面并映射副本(“写入时复制”)。用户空间程序永远不会看到其他用户空间程序私有的内存。

我相信您可以通过搜索此答案中给出的关键词轻松找到更多详细信息。

【讨论】:

  • 谢谢@Felix Palmen。所以这一切都取决于操作系统?没有任何技巧可以强制进程写入特定的物理地址吗?
  • @Guillermo.D.S.还要查找 MMU(内存管理单元).. 地址的转换是在在硬件中完成的,所以,不,对于没有内核权限的进程没有办法,在至少不是没有硬件缺陷或操作系统本身存在一些可利用的漏洞。只有内核才能设置 MMU 使用的页表。
  • 确实有有时特定于操作系统的方式(例如,在 intel linux 下,您可以映射 /dev/mem)。但这是高度特定于平台和架构的。
  • @Ctx 是的,但是如果有这样的机制,它们通常会保留给某些“特权”进程。而且它仍然是内核实际访问物理内存。
  • @FelixPalmen 是的,当然,你必须是 root(或更改 /dev/mem 的权限)。但是不,那不是内核,而是页面直接映射到进程虚拟内存中
【解决方案2】:

来自wikipedia:fork 操作为孩子创建了一个单独的地址空间。子进程拥有父进程所有内存段的精确副本。

所以基本上你创建了一个新进程,其中包含原始进程内存的不同副本。 您更改了复制进程的内存中的某些内容,这些内容是相同的,但只是一个副本,并希望在原始进程中看到它。 通常,进程不直接共享内存。

【讨论】:

    猜你喜欢
    • 2014-04-24
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2011-07-18
    • 1970-01-01
    • 2011-04-02
    • 2012-10-10
    • 2011-03-27
    相关资源
    最近更新 更多