【Linux】复制进程、进程地址空间以及写实拷贝

目录

复制进程fork()方法原型

父子进程

父子进程的pid

物理地址和逻辑地址

交换空间

 写实拷贝


复制进程fork()方法原型

pid_t fork(void);

        pid_t是int类型代表进程的pid号

Linux内核2.4.0定义:

        typedef int  __kernel_pid_t;

        typedef __kernel_pid_t   pid_t;

        每一个进程的pid都是唯一的,同一个程序每次运行都会产生一个新进程,pid不一样但他们的名字是一样的。

【Linux】复制进程、进程地址空间以及写实拷贝_第1张图片

理论上可以产生int表示的上限个进程。每一个进程都有一个PCB(内存控制块,是一个结构体struct task_struct),里面包含pid等信息。


父子进程

        fork函数复制当前进程生成一个新进程,调用fork的为父进程,新生成的为子进程。fork在父子进程中都会有返回值:父进程中返回子进程的pid,子进程创建成功返回0,创建失败返回-1。

        所有父进程的资源都拷贝给子进程(父进程定义的东西子进程都有),父子进程一起执行,子进程从fork()返回之后开始执行(所以不会无限执行)。

使用父子进程可以用同一套代码完成不同的事情

        下面使用父子进程分别打印两个字符串

【Linux】复制进程、进程地址空间以及写实拷贝_第2张图片

输出,父子进程并发执行

【Linux】复制进程、进程地址空间以及写实拷贝_第3张图片


父子进程的pid

pid从1开始往大增长,父进程的pid要比子进程小。

getpid()可以得到自己的pid

getppid()可以得到父进程的pid

【Linux】复制进程、进程地址空间以及写实拷贝_第4张图片

父子进程是相对的,子进程再用fork那它就是fork出来进程的父进程了


物理地址和逻辑地址

逻辑地址是指在应用程序角度看到的内存单元、存储单元、网络主机的地址。

物理地址是数据在存储器中的地址。每一个字节单元给以一个唯一的存储器地址。又叫实际地址或绝对地址。

在父进程和子进程中,同一个变量的输出的地址是相同的

【Linux】复制进程、进程地址空间以及写实拷贝_第5张图片

        但是它们使用的是不同的空间,可以看到它们存放不同的数值,这可以证明它们的物理地址不是相同的,只是逻辑地址相同。程序输出的都是逻辑地址(相对nul偏移量),物理地址是看不到的。

上面代码中n作为临时变量离起始位置偏移量很远:

下面以32位操作系统为例:

        每一个进程的逻辑地址都是由存放代码段(函数)、数据段(全局变量)、堆(new/malloc)、栈(临时变量)、内核的空间构成,并依次远离0x0000 0000位置。如下图:

【Linux】复制进程、进程地址空间以及写实拷贝_第6张图片

       堆往0xffff ffff方向增长,栈往0x0000 0000方向增长。另外代码段初始位置到0x00000000是有一定空间的,这些空间不能被使用代码段的初始地址:0x0804 8000。 4G空间不一定全部用完,代码少的时候代码段大约会使用一页(4k)。

        栈(以栈帧为单位)地址从是从0xbfff ffff开始增长,栈内的变量的地址还是从小到大地址使用的,为了保证程序的安全性,栈不是贴着内核开始增长的。

        每个进程都有一块逻辑地址的空间,这也是不同程序中输出变量的地址可能相同的原因。

这是64位操作系统的:

【Linux】复制进程、进程地址空间以及写实拷贝_第7张图片

十六进制的1000转化成十进制为4096——4k,一个页面大小

malloc时如果没有free,当进程结束时,系统会自动回收空间。如果malloc的少程序运行时间短,不free并不会导致内存泄漏,而且因为有交换空间,我们可以申请比物理内存剩余大一点的内存空间。

32位系统malloc申请空间理论值<3G(考虑当前物理内存剩余空间+虚拟内存剩余空间大小)

【Linux】复制进程、进程地址空间以及写实拷贝_第8张图片

交换空间

Linux的交换空间是一段虚拟内存。虚拟内存不是内存,而是硬盘上的一段空闲空间。

虚拟内存为每个进程提供了一个一致的、私有的地址空间,它让每个进程产生了一种自己在独享主存的错觉(每个进程拥有一片连续完整的内存空间)。

这样会更加有效地管理内存并减少出错。当物理内存不足时,将会使用虚拟内存,但它的访问速度没有内存快。当使用虚拟内存中的东西时,虚拟内存将往物理内存回调。


 

 写实拷贝

        如果父子进程用的统一变量的值是一样的,则让它们使用同一物理空间,当父或子进程的变量更改了再给它们分不同空间,这样提高fork的效率。

    当它们用同一空间时,会有一个变量记录用这个空间的进程数量,如果一个进程结束,引用计数-1,另一个可以继续用,不会将这个空间释放。

你可能感兴趣的:(Linux,linux,运维,服务器)