进程概念,进程状态,虚拟地址空间,环境变量

关于进程的理解:

  • 进程的概念:
    进程是运行着的程序,是系统运行程序的基本单位,进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。程序 一系列有序的指令集合,存储在硬盘中是静态的代码
  • 什么是PCB:
    想要运行程序,既:程序的数据和指令想要被cpu处理,第一步就是将代码和数据加载到内存中,并通过建立PCB控制块(task_struct结构体),建立进程。task_struct结构体是记录了进程的相关信息的数据结构,它包括:描述信息:内存指针,程序计数器,上下文数据,进程标识符PID,IO信息,进程状态等信息。操作系统就是通过PCB管理进程。

Linux进程的六种状态(R、S、D、T、Z、X)

  • R(可执行状态),只有处于R态的进程才有可能在CPU上运行,进程控制块PCB会被放入CPU的可执行队列中(一个进程只能出现在一个CPU的可执行队列中),进程调度器从对应的可执行队列中选择一个进程在CPU上执行。
  • S 可中断的睡眠状态,处于这个状态的进程因为等待某事件的发生(比如等待插座连接,等待信号量),而被挂起。这些进程的task_struct的中的结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发,或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。
  • D 不可中断的睡眠状态TASK_UNINTERRUPTIBLE与S状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。否则你将惊奇的发现,kill-9竟然杀不死一个正在睡眠的进程了!于是我们也很好理解,为什么PS命令看到的进程几乎不会出现D状态,而总是S(可中断休眠状态)。而D(不可中断休眠状态)存在的意义就在于,内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程(这个插入的流程可能只存在于内核态,也可能延伸到用户态),于是原有的流程就被中断了。(参见的的“linux的内核异步中断浅析”)在进程对某些硬件进行操作时(比如进程调用读取系统调 用对某个设备文件进行读操作,而读系统调用最终执行到对应设备驱动的代码,并与对应的物理设备进行交互),可能需要使D状态对进程进行保护,以避免进程与设备交互的过程被打断,造成设备陷入不可控的状态。这种情况下的状态总是非常短暂的,通过PS的命令基本上不可能捕捉到.linux系统中也存在容易捕捉D状态。执行的vfork的系统调用后,父进程将进入TASK_UNINTERRUPTIBLE状态,直到子进程调用exit或exec(参见“神奇的vfork”)。
  • T (TASK_STOPPED或TASK_TRACED)暂停状态或跟踪状态
    向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于TASK_UNINTERRUPTIBLE状态而不响应信号)。(SIGSTOP与SIGKILL信号一样,是非常强制的。不允许用户进程通过信号系列的系统调用重新设置对应的信号处理函数。)向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。
    当进程正在被跟踪时,它处于TASK_TRACED这个特殊的状态“。正在被跟踪“指的是进程暂停下来,等待跟踪它的进程对它进行操作。比如在GDB中对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于TASK_TRACED状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态。
    对于进程本身来说,TASK_STOPPED和TASK_TRACED状态很类似,都是表示进程暂停下来。而TASK_TRACED状态相当于在TASK_STOPPED之上多了一层保护,处于TASK_TRACED状态的进 程不能响应SIGCONT信号而被唤醒。只能等到调试进程通过ptrace的的系统调用执行PTRACE_CONT,PTRACE_DETACH等操作(通过ptrace的的系统调用的参数指定操作)或调试进程退出,被调试的进程才能恢复TASK_RUNNING状态。
  • Z (TASK_DEAD - EXIT_ZOMBIE)僵死状态,进程在退出的过程中,处于TASK_DEAD状态。在这个退出过程中,进程占有的所有资源将被回收,除了task_struct中的结构(以及少数资源)以外。于是进程就只剩下的task_struct的这么个空壳,故称为僵尸。之所以保留的是task_struct,是因为task_struct中的里面保存了进程的退出码,以及一些统计信息。而其父进程很可能会关心这些信息。比如在外壳中,$?变量就保存了最后一个退出的前台进程的退出码,而这个退出码往往被作为如果语句的判断条件。当然,内核也可以将这些信息保存在别的地方,而将task_struct中的结构释放掉,以节省一些空间。但是使用的是task_struct结构更为方便,因为在内核中已经建立了从PID到的task_struct中查找关系,还有进程间的父子关系。释放掉的task_struct中,则需要建立一些新的数据结构,以便让父进程找到它的子进程的退出信息。
    父进程可以通过 wait系列的系统调用(如WA IT4,waitid)来等待某个或某些子进程的退出,并获取它的退出信息。然后wait系列的系统调用会顺便将子进程的尸体(的task_struct)也释放掉。子进程在退出的过程中,内核会给其父进程发送一个信号,通知父进程来“收尸”。这个信号默认是SIGCHLD,但是在通过克隆系统调用创建子进程时,可以设置这个信号。只要父进程不退出,这个僵尸状态的子进程就一直存在。那么如果父进程退出了呢,谁又来给子进程“收尸”?当进程退出的时候,会将它的所有子进程都托管给别的进程(使之成为别的进程的子进程)。托管给谁呢?可能是退出进程所在进程组的下一个进程(如果存在的话),或者是1号进程。所以每个进程,每时每刻都有父进程存在除非它是1号进程。
    1号进程:PID为1的进程,又称初始化进程.linux系统启动后,第一个被创建的用户态进程就是初始化进程它有两项使命:(1)执行系统初始化脚本,创建一系列的进程(它们都是初始化进程的子孙(2)在一个死循环中等待其子进程的退出事件,并调用waitid系统调用来完成“收尸”工作;初始化进程不会被暂停,也不会被杀死这是由内来保证的。它在等待子进程退出的过程中处TASK_INTERRUPTIBLE状态,“收尸”过程中则处于TASK_RUNNING状态。
    僵尸进程的危害:资源泄露。一个进程所能创建的进程是有限的,并且资源没有完全回收会占据内存资源。处理方法:退出父进程(父进程退出,子进程保存退出原因没有意义,因此子进程被完全释放)。
    孤儿进程:父进程先于子进程退出,则子进程成为孤儿进程,这个孤儿进程的父进程成为了1号进程,并且这个孤儿进程运行在后台不会成为僵尸进程,因为1号进程随时关注子进程退出。
    X (TASK_DEAD - EXIT_DEAD)退出状态
    而进程在退出过程中也可能不会保留它的task_struct中的。比如这个进程是多线程程序中被分离过的进程(进程?线程?参见“的Linux的线程浅析”)。或者父进程通过设置SIGCHLD信号的处理程序为SIG_IGN,显式的忽略了SIGCHLD信号。(这是POSIX的规定,尽管子进程的退出信号可以被设置为SIGCHLD以外的其他信号。)此时,进程将被置于EXIT_DEAD退出状态,这意味着接下来的代码立即就会将该进程彻底释放。所以EXIT_DEAD状态是非常短暂的,几乎不可能通过PS命令捕捉到。

该部分转自https://blog.csdn.net/wjd_231/article/details/81432999

程序地址空间:

在这里插入图片描述

  • 虚拟地址空间:程序(进程)不是直接在内存上跑的,建立进程时候,操作系统会为每一个进程分配一段虚拟地址空间,再通过页表映射到内存上。程序运行时访问的不是实际的物理内存地址,而是一个虚拟地址。然后再通过页表映射到物理地址上进行操作。
  • 为什么要使用虚拟地址空间:进程访问的是连续的虚拟地址空间,最终通过页表映射到物理内存上实现数据离散式存储—提高内存访问率并且可以在页表中实现内存的访问控制 。进一步提高了进程的独立性。进程地址空间如果不隔离。那么程序都是直接访问物理内存,恶意程序可以随意修改别的进程的内存数据,以达到破坏的目的。有些非恶意的,但是有 bug 的程序也可能不小心修改了其它程序的内存数据,就会导致其它程序的运行出现异常。这种情况对用户来说是无法容忍的,因为用户希望使用计算机的时候,其中一个任务失败了,至少不能影响其它的任务。
    分页式虚拟内存管理:
    虚拟地址:页号+页内偏移(将硬盘按照页大小分为 n 页)
    物理地址:物理块号 * 块大小(等于页面大小)+页面偏移

环境变量:

环境变量:配置系统运行环境参数变量,使系统运行环境配置更加简单灵活,Linux是一个多用户多任务的操作系统,可以在Linux中为不同的用户设置不同的运行环境,具体做法是设置不同用户的环境变量(称之为 Linux中定制的环境变量)。但是仍有些环境变量是用户都需要的,我们称之为Linux中常见的环境变量。
Linux中常见的环境变量有:
1.PATH:指定命令的搜索路径
2.HOME:指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
3.HISTSIZE:指保存历史命令记录的条数。
4.LOGNAME:指当前用户的登录名。
5.HOSTNAME:指主机的名称,许多应用程序如果要用到主机名的话,通常是从这个环境变量中来取得的。
6.SHELL:指当前用户用的是哪种Shell。
7.LANG/LANGUGE:和语言相关的环境变量,使用多种语言的用户可以修改此环境变量。
8.MAIL:指当前用户的邮件存放目录。
9.PS1:命令基本提示符,对于root用户是#,对于普通用户是$。
10.PS2:附属提示符,默认是“>”。
Linux设置环境变量的方法
一、在/etc/profile文件中添加变量 对所有用户生效(永久的)
用vim在文件/etc/profile文件中增加变量,该变量将会对Linux下所有用户有效,并且是“永久的”。
注:修改文件后要想马上生效还要运行source /etc/profile不然只能在下次重进此用户时生效。

二、在用户目录下的.bash_profile文件中增加变量 【对单一用户生效(永久的)】
用vim ~/.bash_profile文件中增加变量,改变量仅会对当前用户有效,并且是“永久的”。

注:修改文件后要想马上生效还要运行 source ~/.bash_profile不然只能在下次重进此用户时生效。

三、直接运行export命令定义变量 【只对当前shell(BASH)有效(临时的)】
在shell的命令行下直接使用export 变量名=变量值
定义变量,该变量只在当前的shell(BASH)或其子shell(BASH)下是有效的,shell关闭了,变量也就失效了,再打开新shell时就没有这个变量,需要使用的话还需要重新定义。如:
export $ PATH="$ PATH:路径1:路径2:…:路径n” (或“PATH=$PATH:路径1:路径2:…:路径n" ),意思是可执行文件的路径包括原先设定的路径,也包括从“路径1”到“路径n”的所有路径。当用户输入一个一串字符并按回车后,shell会依次在这些路径里找对应的可执行文件并交给系统核心执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值