当前位置:   article > 正文

Linux:虚拟地址空间&写时拷贝_linux写时拷贝

linux写时拷贝

写时拷贝

主要是提升子进程创建效率,避免不必要的内存消耗
malloc开辟一块内存空间,其实只是先分配了一个虚拟地址,物理内存并没有直接被开辟,当第一次要修改空间数据的时候才会被分配

父子进程的页表都指向同一物理空间
因为进程具有独立性,当子进程改变数据的时候
os会为子进程重新开辟空间,并且把原始数据进行拷贝,
子进程就指向新物理空间,os只修改页表右侧,不会改左侧

fork的两个返回值,同一个变量怎么有不同的值

因为return的时候,id属于父进程的地址栈上定义的变量
fork内部,return会被执行两次,
return的本质是通过寄存器将值返回给接收返回值的变量中,谁先返回,谁就先发生写时拷贝
所以一个变量有两个值

为什么存在虚拟地址空间

保护内存,防止进程越界访问
进程出现野指针,在页表中没有映射关系
页表转换就会失败,进程无法访问内存

Linux内存管理

进程申请空间时,os只是扩大虚拟地址空间,真正访问时才会在物理空间开辟

这样内存管理和进程管理通过虚拟地址空间进行解耦

进程具有独立性:

代码和数据都是独立的,一般情况下fork后,父子进程共享所有代码,子进程拥有所有代码,只不过子进程只能从fork后执行
fork后,修改子进程的eip,也就是程序计数器,可以让子进程重头执行

写入的时候进行深拷贝就是写时拷贝

为什么采用写时拷贝

为什么不直接将代码共享,数据分开呢
父进程的数据,子进程不一定全用,如果全部拷贝,这样会增加fork运行的成本
写时拷贝是拷贝数据的最小成本

进程创建

fork后有两种情况
子进程做和父进程类似的事
子进程做别的事

进程终止

main函数是程序入口,总是会return 0
这个0是

为什么是0

0表示正确,非0表示错误
return是进程退出码,表明进程退出的信息
这个信息是让父进程读取

代码跑完,执行正确
代码跑完,执行错误
进程异常,后面讲
echo $?打印上一次进程的退出码
比如ls,成功执行,查看后退出码就是0
查看的文件不存在,退出码就是别的数

1.main函数中return表示代码退出
2.调用exit,任何地方调用都能退出,退出码是括号内的值
终止进程后会刷新缓冲区,_exit不会

进程终止,内核做了什么

进程进入z状态,父进程读取退出信息,并设置为x状态,然后释放子进程资源
进程终止时,内核结构两个学的数据结构定义出的对象,os可能并不会释放这些对象
os会维护一个进程释放链表,os创建新进程时,直接将这些pcb拿出来
这是内核的数据结构缓冲池

进程等待

解决内存泄露问题(僵尸进程造成内存泄露)
获取子进程退出状态

进程退出有退出码,exit的结果需要被父进程获取

写时拷贝:

通常,父子代码共享,父子再不写入时,数据也是共享的,当任意一方试图写入,便以写时拷贝的方式各自一份副本
来源比特
父进程创建子进程后,父子进程通过页表结构映射到同一块物理内存;

  • 两个进程对物理内存区域的值都不修改的时候,它们各自的进程虚拟地址与物理内存的映射关系是一致没有改变的;
  • 其中一个进程修改数据的时候,操作系统才会去修改这个进程的映射关系(属于深拷贝)
  • fork函数在拷贝时也拷贝了页表关系,父子进程的全局变量值都在各自数据段中;
  • 两个进程的进程虚拟地址空间中的数据段,通过页表关系指向了同一个物理地址;
  • 其中一个进程修改全局变量的值,操作系统会在物理内存中重新开辟一段空间保存修改之后的值(也就是开辟蓝色线指向的空间),改掉映射关系;
  • 如果直接在原物理空间上修改值,就会影响另一个进程;
  • 修改后会修改物理地址和页表块号的映射关系。但是虚拟地址值不变

结论:
父子进程代码是共享的(只是代码一样,实质上是有各自的代码段 ),但是它们的数据是各自独有的.*

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/163361
推荐阅读
相关标签
  

闽ICP备14008679号