我很困惑。我已经读过,当父进程创建子进程时, child获取其父级地址空间的副本。复制意味着什么? 如果我使用下面的代码,那么它会打印相同的变量'a'的地址 案例。即在儿童和父母的情况下。那么这里发生了什么?
int main () { pid_t pid; int *a = (int *)malloc(4); printf ("heap pointer %p\n", a); pid = fork(); if (pid < 0) { fprintf (stderr, "Fork Failed"); exit(-1); } else if (pid == 0) { printf ("Child\n"); printf ("in child heap pointer %p\n", a); } else {
wait (NULL); printf ("Child Complete\n"); printf ("in parent heap pointer %p\n", a); exit(0); }
}
答案 0 :(得分:18)
子级获取父级地址空间的精确副本,在许多情况下,父级地址空间可能与父地址空间的格式相同。我必须指出,每个人都有自己的虚拟地址空间用于它的内存,这样每个人可以在同一地址拥有相同的数据,但是在不同的地址空间中。此外,linux在创建子进程时使用copy on write。这意味着父和子将共享父地址空间,直到其中一个进行写入,此时内存将物理复制到子进程。这会在exec
新进程时消除不需要的副本。由于您只是要用新的可执行文件覆盖内存,为什么还要复制呢?
答案 1 :(得分:2)
复制意味着,与虚拟地址空间的位相同的副本。对于所有意图和目的,这两个副本是无法区分的,直到您开始写入一个(这些更改在另一个副本中不可见)。
答案 2 :(得分:1)
你得到两个堆,因为内存地址被转换为物理内存的不同部分,所以它们都具有相同的虚拟内存地址。
答案 3 :(得分:1)
是的,您将获得相同的虚拟地址,但请记住每个虚拟地址都有自己的进程虚拟地址空间。 直到有一个Copy-On-Write操作完成所有内容的共享。 因此,当您尝试strcpy或任何写入操作时,会发生写入时复制,这意味着将为子进程更新指针a的子进程虚拟地址,但父进程不会更新。
答案 4 :(得分:0)
使用fork()
子进程接收一个新的地址空间,其中复制了父地址空间的所有内容(实际上,现代内核使用 copy-on-write )。
这意味着如果您在流程中修改a
或其指向的值,则其他流程仍会看到旧值。