以下代码:
main() {
int *p = (int *)malloc(2*sizeof(int)) ;
if(fork()) wait() ;
else *p = 10 ;
}
我想知道,当我们fork时,子进程也会在其进程空间中接收malloced块。也就是说,在上面的代码中可以安全地说 - :
*p = 10 ;
答案 0 :(得分:3)
是的,孩子将拥有适当的malloc()
内存。
首先,要知道有两个内存管理器:
sbrk()
系统调用完成的。malloc()
uses sbrk()
从内核请求内存,然后通过分块来管理它,记住内存是如何分割的,然后在free()
编辑时将它们标记为可用(有时perform something similar to garbage collection)。那就是说,malloc()
对内存的作用对Linux内核完全透明。它实际上只是一个或两个链接列表,您可以自己实现。 Linux内核将您的内存视为分配给您的流程及其内容的页面。
当你致电fork()
时(强调我的):
- 使用单个线程创建子进程 - 调用fork()的线程。 父级的整个虚拟地址空间在子级中复制,包括互斥锁,条件变量和其他pthreads对象的状态;使用pthread_atfork(3)可能有助于处理这可能导致的问题。
- 子项继承父组的打开文件描述符的副本。子节点中的每个文件描述符引用相同的打开文件描述(请参阅open(2))作为父节点中的相应文件描述符。这意味着两个描述符共享打开文件状态标志,当前文件偏移和信号驱动的I / O属性(请参阅fcntl(2)中的F_SETOWN和F_SETSIG的描述)。
- 子进程继承父组的开放消息队列描述符的副本(请参阅mq_overview(7))。子节点中的每个描述符引用与父节点中相应描述符相同的开放消息队列描述。这意味着两个描述符共享相同的标志(mq_flags)。
- 子项继承父组的打开目录流的副本(请参阅opendir(3))。 POSIX.1-2001表示父节点和子节点中相应的目录流可以共享目录流定位;在Linux / glibc上他们没有。
所以fork()
不仅复制整个虚拟地址空间,还复制所有互斥体,文件描述符以及父节点已打开的各种资源。复制的部分虚拟地址空间是malloc()
的链接列表。因此,在fork()
之后,两个进程的malloc()
ed内存相等,信息malloc()
保持不变,分配的内存也相同。但是,它们现在位于不同的内存页面上。
附带信息:有人可能认为fork()
是一项非常昂贵的操作。但是(从手册页):
在Linux下,
fork()
是使用copy-on-write页面实现的,因此它所带来的唯一代价是复制父页面表所需的时间和内存,并创建一个唯一的孩子的任务结构。
这基本上表示在fork()
上,没有进行实际复制,但如果孩子试图修改它们,则会将页面标记为。实际上,如果孩子只从该内存中读取,或者完全忽略它,则没有副本开销。这对于常见的fork()
/ exec()
模式非常重要。