fork 创建一个子进程时,会创建一个新的地址空间,并且拷贝父进程的资源,然后就爱那个会有两种行为:
1.执行从父进程那里拷贝过来的代码段
2.调用exec执行一个新的代码段
当调用exec时,新的程序替换了当前进程的正文数据、堆和栈段,前面拷贝的就相当于白费了。所有就有了“写时复制”技术。
写时复制
即复制的时候,页帧并没有复制,而是共享页帧,页帧被分享后就不能修改,即页帧被保护,当父进程或子进程试图写入一个共享的页帧,就会发生异常,这是内核就把这个页复制到一个新的页帧,并标记为可写,原来的额页帧仍被保护。
vfork就把事情做绝了,所有有关于内存的东西都不复制了,父子进程的内存是完全共享的。但是这样一来又有问题了,虽然用户程序可以设计很多方法来避免父子进程间的访存冲突。但是关键的一点,父子进程共用着栈,这可不由用户程序控制的。一个进程进行了关于函数调用或返回的操作,则另一个进程的调用栈(实际上就是同一个栈)也被影响了。这样的程序没法运行下去。
所以,vfork有个限制,子进程生成后,父进程在vfork中被内核挂起,直到子进程有了自己的内存空间(exec**)或退出(_exit)。并且,在此之前,子进程不能从调用vfork的函数中返回(同时,不能修改栈上变量、不能继续调用除_exit或exec系列之外的函数,否则父进程的数据可能被改写)。
页表
页表是一种特殊的数据结构,放在系统空间的页表区,存放逻辑页与物理页帧的对应关系。 每一个进程都拥有一个自己的页表,PCB表中有指针指向页表。
基本分页存储管理方式
用固定大小的页(Page)来描述逻辑地址空间,用相同大小的页框(Frame)来描述物理内存空间,由操作系统实现从逻辑页到物理页框的页面映射,同时负责对所有页的管理和进程运行的控制。
页帧(页框)
分页管理时,将若干个字节视为一页,比如4 byte,此时内存变成了连续的页,即内存为页数组,每一页物理内存叫做页帧,以页为单位进行编号,称为页帧号,页帧和页框是一个东西。