Linux--进程概念02

回顾:

进程概念:进程就是运行中的程序,在系统角度,是对程序运行过程的动态描述(标识符,上下文数据,内存指针...),在linux下就是一个task_struct结构体,也被称为pcb--进程控制块;通过这个pcb系统对程序进行管理和调度。

进程状态:表示当前进程该如何被管理以及调度。

        运行,可中断休眠,不可中断休眠,停止,僵尸.

        僵尸进程:处于僵尸态的进程,一个退出运行但资源未被完全释放的进程。

                         产生:子进程先于父进程退出,为了保存退出返回值,因此没有完全释放资源。

        危害:资源泄露。(一个用户所能创建的进程数量,内存资源...)

        避免:进程等待。

        孤儿进程:父进程先于子进程退出,子进程成为孤儿进程。

        特性:运行在后台,父进程成为1号进程。

        孤儿进程退出后就不会成为僵尸进程。

进程创建

fork函数

头文件:#include<unisd.h>

函数原型:pid_t fork(void)

返回值:子进程返回0,父进程返回子进程的pid,出错返回0

进程调用fork后,内核将:

  1. 分配新的内存块和内核数据结构给子进程
  2. 将父进程部分数据结构内容拷贝至子进程
  3. 添加子进程至系统进程列表中
  4. fork返回,开始调度器调度

写时拷贝

        通常父子代码共享,父子不在分别写入,数据也是共享的,但当任意一方试图写入时,便以写时拷贝的方式各自一份副本。

        子进程复制了父进程的大部分信息,因此子进程有自己的变量,但是通过页表映射后与父进程访问的是同一物理地址,当这块内存空间中的数据即将要修改,则给子进程重新开辟内存空间,并拷贝数据。

作用:为了提升子进程的创建效率,避免不必要的内存消耗。

例:malloc函数:动态申请一块空间--其实只是先分配一个虚拟地址(物理地址并没有直接被开辟),当第一次修改空间数据时才会被分配。

 环境变量 

环境变量:保存了当前程序运行环境参数的变量

优点:即时生效;让运行环境配置更加灵活,通过环境变量可以给程序传递数据。

终端shell中的变量其实有两种:环境变量,普通变量

        环境变量居有进程间的继承特性,但普通变量没有。

接口:char *getenv(char *name);

指令:

  •  env:查看所有环境变量
  • echo:打印指定内容
  • export:声明一个变量为环境变量
  • set:查看所有变量
  • unset:删除一个变量

在程序中访问环境变量:

  1. getenv()接口
  2. main函数第三个参数 mian(int argc,char* argv,char* env)
  3. 全局变量:extern char** environ

 程序地址空间

程序地址空间:进程的虚拟地址空间。

        系统为每一个进程运行通过mm_struct结构体(linux)下所描述的一个虚拟的,连续的,完整的地址空间,其实我们进程中访问内存时看到的地址都是虚拟地址,经过页表映射之后得到物理地址进而访问物理地址。

        好处:

  1. 每一个进程都有一个完整独立的虚拟地址空间,则地址可以随便使用,不担心使用冲突,地址管理更加方便。
  2. 经过页表映射可以将数据存储在物理地址的任意位置,实现通过页表的离散式存储,提高物理内存的利用率。
  3. 在进行页表映射的之后可以进行访问权限的控制。

内存管理方式

  • 分段式内存管理
  • 分页式内存管理
  • 段页式内存管理

分段式内存管理:将一个整体的地址空间划分为多个段(代码段,数据段,堆区,栈....)

        作用:更加利于编译器对于地址的管理。

        重要的两要素:段表,地址组成。

        虚拟地址组成:段号,段中的偏移量。

        段表:是一种数据结构,其中描述的信息,段号,物理内存的一个起始地址。

        通过段号找到段表项,得到一块物理内存的起始地址。

        物理内存起始地址+偏移量就是实际数据存储在物理内存中的位置。

 分页式内存管理:将一个整体的地址空间划分为大量的小分页page(一般默认都是4096字节为一页)。

        作用:实现数据的离散式存储,提高内存利用率。

        两个关键要素:页表+虚拟地址组成

                页表,页号,物理内存块起始地址,缺页中断位,访问权限位...

        通过虚拟地址中的页号,在页表中找到对应的页表项,得到一个物理地址的起始地址,加上页内偏移就是实际访问位置。

        不同于分段式管理,分段式利于地址管理,而分页式更倾向于碎片化管理,提高内存利用率以及内存访问控制。

段页式内存管理:先将地址空间分段,然后对每一分段进行分页式管理。


访问权限位:标记当前的地址能够进行什么样的操作

        比如:0号地址,也就是NULL,这个地址既不可读,也不可写,因此一旦解引用或则修改内存就会报错。

        比如:const修饰的常变量,具有常量特性,其实就是访问权限上只读。


缺页中断:当进程要访问一块内存的时候,经过页表映射是发现缺页中断位被置位(这个地址原先的数据不在内存中),则触发缺页中断。

        内存交换:一个程序运行要占据大量内存,但是物理内存是有限的,意味这内存总有耗尽的时候,如果没有内存交换技术,则内存耗尽,则意味这新程序没法运行。因此产生了一些需要,按照某种特定规则,将内存中不常用的数据从内存中移出,存放到硬盘,然后腾出内存供当前程序使用。但当我们要访问数据时,会发现我们要访问的数据就是刚移出去的数据,则会触发缺页中断。

        触发缺页中断后,就需要重新进行内存置换,将数据中交换分区换到内存中进行访问。


内存置换算法:内存不够的时候,把哪些数据移出放到交换分区上存储

        经典算法:LRU--最久未使用      LFU--最少未使用

一旦产生大量的内存置换,运行效率就会降低,因为硬盘的吞吐量是非常小的。

交换分区是安装系统时分配好的,硬盘的一部分被分为交换分区,一部分被分为文件系统分区(文件存储),交换分区没有固定大小,一般是内存的2倍。

 退出

如何中止一个进程呢?

  1. 在main函数中return。               仅在main函数中使用时退出运行程序。 return是中止一个函数,并返回一个数据;main函数是程序的入口函数,入口函数一旦退出,程序运行就会终止。 

  2. 库函数:void exit(int retval)       在任意位置调用,都可以退出程序运行。系统调用接口是操纵系统向上层提供的用于访问内核的接口,功能相对单一。大佬针对经典场景,对系统调用接口进行封装,封装出了适用于典型场景的库函数。


  3. 系统调用接口:void _exit(int retval) 在任意位置调用,都可以退出程序运行。

exit和_exit的区别是在于程序运行前,是否会将缓冲区中的数据进行刷新写入文件中。

进程退出返回值的意义:

        return和exit给与的数据其实就是进程的退出码。

        作用:一个程序运行起来肯定是为了完成一个任务,但是这个任务完成的如何外界是如何得知呢?

        因此就必须有这个程序的退出码,来表示当前进程处理的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Exile_001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值