第六十二讲——linux内核 虽然linux内核源码很长,有上千万行,但是实际上我们使用到的功能是比较有限的,在编译内核的时候按照我们的需求进行编译,编译完成后内核的大小可能只有几十兆,在经过压缩,几兆大小也是可以实现的。 但是对于red hat、debian等发行版来说,为了使操作系统弄安装在各个平台上,且内核不臃肿,只能够将功能模块化,这些模块是被能被进程使用的,只有内核才能调用,所以这些外部的模块称你为ko(kernel object)内核对象,因此内核由核心和内核对象组成。内核是动态加载模块的,模块存放在/lib/modules目录下。 系统上可以有多个内核并存,且每个内核在/lib/modules目录下都有一个跟内核版本号完全相同的目录,即以内核版本号命名的目录,在这个目录下有对应内核所需要的各种外围模块,而模块同各应用程序一样,存在依赖关系。在内核的内部有一个模块依赖关系的文件,用来识别这种依赖关系。 在大多的系统上,内核的命名为vmlinuz /lib/modules下的*.dep文件是内核的模块依赖关系(自动生成) /lib/modules下的*.*map为映射表,或者叫符号链接表 /lib/modules/内核版本号/kernel 下为内核模块 arch 平台驱动(驱动CPU) crypto 加密解密相关 drives 驱动 fs 文件系统 kernel 内核自身的其他功能 lib 库 mm 内存管理 net 网络管理(TCP/IP协议栈,并不是网络驱动) sound 声卡 那么此时问题来了,我们的驱动都放在了/lib/modules下,而我们的内核在驱动根文件系统时是需要先驱动硬盘,而硬盘的驱动在根文件系统下,这样就进退两难了,难道我们还得将驱动程序放入内核中?那样一来我们费劲心思模块化减少内核体积的意义便荡然无存了。 于是我们只能妥协,寻找一个中间人来完成驱动硬盘的工作,这个中间人只能向内核提供硬盘的驱动程序,用以挂载根文件系统。 那么这个中间文件是否会臃肿? 这个我们就得从操作系统的安装说起,在操作系统安装的过程中,安装程序会知道内核要访问的“根”在哪个地方,也会知道设备的类型,所需要的驱动程序,于是在安装完成的最后一个步骤安装程序会通过脚本或者命令自动收集内核访问这个设备所需要的程序有哪些,并动态生成这个中间文件,而这个文件就是一个桥接,将内核与文件系统建立联系。 那么这个中间文件是如何被访问的?它不存放在硬盘中? 我们之前说过,内核要访问任何文件都必须通过文件系统来访问,这样的设计风格、访问接口、访问方法才能够一致。这也就意味着这个中间文件得是一个独立的文件系统,但是我们之前也说过,访问任何文件系统得先驱动硬盘,且得通过根文件系统进行访问,于是这个中间的文件系统就是一个根文件系统,我们称之为虚根,只是用于临时过渡,在一个操作系统中虽然两个根文件系统不能同时存在,但是根文件系统是可以切换的。 当虚根的任务完成以后就会自动切换到真正的根文件系统。 #chroot命令就能够完成根目录的切换,可以将一个临时的目录作为根来使用。使用的时候只需要在命令后跟上目录即可。 #chroot /path/to/somewhere 在临时目录下应当有/bin目录,且/bin下应有一个bash程序用于与计算机交互,这样就可以运行了?实际上不是的,从我们前面所学的bash环境的配置文件来看,至少是需要一些配置文件的,我们也说过,程序的运行是需要依赖库文件的,因此我们可以大胆猜测,在临时目录下仅有/bin/bash是不能够切换成功的,因为bash程序不能成功的运行。 事实上,单独的bash不能成功切换根,此时我们需要将bash程序所依赖的库文件cp到临时目录的/lib下,因为临时目录切换为根之后,整个的运行机制是一样的。 #ldd /bin/bash 显示bash程序共享库的依赖关系 #ldd /path/to/somewhere(可执行程序的路径),显示一个程序运行所依赖的库文件。 我们手动将ldd /bin/bash 显示出来的库文件cp到临时目录下的/lib下,再次使用chroot命令切换根,我们会发现切换是切换了,但是提示符什么的就不是我们登录操作系统的时候的提示符了,原因就是我们登录后是bash程序的配置文件生效,才有了命令提示符的格式,我们如果将对应的配置文件放到对应的目录下也可以实现。 由于我们chroot改变了根,于是将临时目录作为根,根下仅有bash程序,也就是说,之前所有的服务都会挂掉,而且只能使用bash的内建命令,所有的外部命令无法使用。 外部命令和内部命令使用的帮助命令是有区别的,内建命令使用—help查看,外部命令使用man命令查看。 通俗点说,我们进行根切换就是画地为牢,将活动限制在一定范围内,而虚根进行切换时,机制同上,但是使用的命令是完全不一样的,虚根的切换时完完全全的切换,在切换时将虚根上的所有文件都搬运到真正的根上。 /proc 内核映射 在rhel5上,借助nash提供的switch_root命令完成根切换,而switch_root就是运行在临时根文件系统上的命令,这个命令能够将临时根中的文件搬运到真实根目录中,并以真实的根目录作为根,虚根这个文件能载入内存,并能够将内存中的一段空间模拟成磁盘空间使用,通常被称为ramdish,在rhel6上叫ramfs,所以在rhel5上这个文件的名字叫initrd,在rhel6上叫initramfs。这个跟红帽操作系统本身没有关系,而是跟红帽采用的机制又关系。 所以,内核要访问根,一般来讲需要两个模块。 一是这个设备的驱动 二是这个设备上的文件系统 我们再来梳理一下系统的系统流程: POST-->BIOS(Boot seqence)-->MBR(boot loader,446byte)-->kernel-->initrd(initramfs)-->/sbin/init 给自己讲linux 2017-01-31 评论 1641 次浏览
第六十一讲——linux的详细启动流程 为了更深层次的理解,再次对linux启动流程进行了解。 当我们在按下开机键的时候,机器会进行自我检测,POST加电自检,自检的程序是出厂的时候就设置好了,在加电自检的时候会将固化在ROM中的程序(指令)映射到物理内存当中,此时CPU就能够读取到RAM中的指令,进行硬件自检的流程,各个硬件,包括CPU、散热风扇是否正常,如果自检通过,则会根据BIOS中定义的设备启动顺序(boot sequence),去找操作系统所在的位置,如果没有启动顺序,设备就会混乱,所以计算机是按照设定好的顺序自上而下的取寻找启动设备的MBR(硬盘的第一个为512字节的扇区,但是当存储设备的容量大于2T的时候,设备采用的是GPT格式),MBR中有一段占据446byte的引导程序(boot loader),boot loader主要用于通过MBR中的分区表查找活动分区,也就是说boot loader能够找到操作系统所在的分区,并加载分区上的操作系统的内核。 当BIOS中设定的启动顺序中的第一个设备不存在MBR的时候,会从第二个设备上寻找,但是当第一个设备上存在MBR但是MBR已损坏时,是不会继续到第二个设备上寻找MBR,这一点我们必须要搞清楚,也就是说,按照BIOS中设定的顺序,存在MBR扇区的设备即为被认定的启动设备。 boot loader接管硬件后BIOS会退出,装在选定的磁盘分区上的内核,我们需要知道的是,内核一般是压缩存放的,boot loader加载完内核到内存后完成解压缩,而后将控制权转交给内核,这个时候内核取代了硬件的整体控制权,此时boot loader 完成工作退出。 kernel在接管硬件的时候必须要能够识别CPU、内存,我们之前说过,驱动程序能够使硬件更好的工作,因此内核在接管硬件时必须要去尝试探测每一个硬件,看看这个硬件的特性是什么,能不能够被驱动,能不能正常工作。 内核能提供文件系统,所以以前常说文件系统时内核的功能。 实现进程的管理 实现内存的管理 实现网络的管理 提供安全功能 提供驱动程序 当内核全面接管硬件以后,会启动init进程(/sbin/init),init是一个可执行的二进制程序,我们需要注意的是,init是用户空间的一个主导程序。因此,所有在用户空间所启用的进程都是由init来管理的,当我们需要和硬件打交道的时候才会切换到内核空间。 POST—>BIOS(boot sequence)-->MBR(boot loader)-->init(/sbin/init) 根所在的分区叫rootfs(根文件系统) 在linux中,根是访问其他任何存储设备的入口,当根挂载完毕就要启动操作系统了。 /bin,/sbin是操作系统自身启动就要用到的,不能独立分区。 kernel启动完成后会自动挂载根文件系统,以实现自引用,我们必须要告诉内核,根在上面位置,我们可以向内核传递一个参数,告诉内核,根在哪一个设备上。这一切的前提是内核能够驱动分区,否则是不能够访问rootfs的,这也就意味着内核必须能够探测到硬件分区,并能够访问这个分区。 如果我们将驱动程序做进内核,内核的体积会变得相当庞大,启动内核时所消耗的资源也就会越多,因此,这些驱动很显然是不能直接做进内核中的,他们是内核的功能,但不应该全部都放进内核。 在linux上,内核是由独特的结构的,从内核的设计结构来说,有两种。 一是单内核:将文件系统、进程管理等做进内核,由一个内核来管理,也就是说,内核靠一个进程来完成所有的功能。 二是微内核:内核很小,只有一个核心,将各种外围的功能做成它的子系统,当需要用到这个功能的时候就调用子系统,将子系统装载进内核。 对于但内核来说,任何一个功能出现问题则会殃及池鱼,因为它们是一体的,但是它的逻辑是相对简单的。 对于微内核来说,模块损坏不会引起全局的动荡,但是微内核因为分为多个模块,因此多模块之间的协调是很复杂的。 在实际的运用上,微内核实现的难度对冲了它所具有的的优势,linux属于单内核,对线程的支持并不是特别的好,线程(LWP:轻量级进程) Windows、solaris属于微内核,从根本上来说,微内核的设计才是真正意义上支持多线程。 给自己讲linux 2017-01-30 评论 1642 次浏览
第六十讲——进程间通信 进程间通信(IPC:inter process communication) 进程间通信是linux操作系统中非常常用的一种机制,我们说过,进程与进程间是相互意识不到存在的,那么进程与进程之间的通信还要到交换机上跑一圈?当然不是的。 一是通过共享内存,一个进程写点数据,另一个进程去读。 二是通过信号(signal)向另一个进程发送一个简短的信号。 三是通过旗语(semaphore),一个进程向另一个进程打个手势之类的。 信号: 使用kill –l可以显示出所有的可用信号。 kill 主要功能是终止一个进程。 但是kill通常用来向一个进程发送信号。 较为重要的信号有: 数字1:SIGHUP,让一个进程不用重启就可以重读配置文件,并让新的配置文件信息生效。 数字2:SIGINI:(Ctrl+C)终止(中断)一个前台进程。 数字9:SIGKILL:杀死一个进程,直接结束进程。 数字15:SIGTERM:终止一个进程,释放资源后终止。 我们制定一个信号的方式可以为: 信号号码:kill -# 信号名称:kill –SIGHUP 信号名称简写:kill –HUP kill 进程号,默认发送的是15号信号。 kill all command(进程名) 只要是叫这个名的进程全部结束 pkill 杀死一个进程,用法同pgrep 我们在执行一个命令的时候,有时候不想直接结束当前程序,又希望能够执行其他程序执行。这时候我们就需要使用到一种机制,一种将当前程序放入后台藏起来,使用的时候又能够取回来的机制。 ctrl + z 将当前进程放入后台藏起来。 fg命令,可以将后台藏起来的命令调入前台。 我们将占据了(终端)命令提示符的进程称为前台进程。 启动后释放命令提示符,在后台默默完成,称为后台进程。 我们在执行命令的时候,在命令前面加一个&符号,就会在执行程序后释放掉命令提示符。 当我们把一个进程从前台送入后台时,默认送给一个stop信号,进程送到后台时为停止状态。 #bg (background):让后台的停止作业继续运行,在后台运行。 #jobs 查看所有的作业(一般是后台的所有作业) 每一个作业都有作业号,作业号不同于进程号,且作业号前有加号“+”。 “+”:表示为被默认操作的作业。 “-”: 表示命令将第二个默认操作的作业。 #bg jobID(作业号),作业号可以省略,默认为带+号的作业。 #fg (jobID)将后台的作业调回前台。 bg和fg是不能够操作进程的,所以可以省略(%)号。 使用kill %jobID 终止一个作业。不加%为终止一个进程。 #vmstat:系统状态查看命令 procs 与进程相关 r:运行队列长度 b:阻塞队列长度 memory 与内存相关 swapd:交换空间已使用大小 free:空闲内存 buff:缓冲 cache:缓存 swap 与交换内存相关,表示从物理内存到swap分区有多少页面换进换出。 si (swap in):从物理内存放到交换内存(多少个页面) so(swap on): 从交换内存调入物理内存(多少个页面) io 与I/O相关 bi (blocks in)有多少个硬盘块调入内存 bo (blocks on)有多少个块同步到硬盘 system 与系统相关 in 中断的个数 cs 上下文切换的次数(进程切换的次数),当指定vmstat的时间间隔时,表示为,这个时间内切换了多少次。 cpu 与CPU相关 us 用户空间占用cpu的百分比 sy 内核空间占用cpu 的百分比 id 空闲的百分比 wa 等待io完成的百分比 st 被偷走的时间,指那些切换进程所消耗掉的时间。 vmstat #(number)刷新间隔,单位为秒 vmstat # # (vmstat 1 5)每隔一秒刷新一次,刷新五次。 uptime命令与top命令的第一行一样。 我们通过查看/proc/meminfo文件,也可以实现查看内存的信息。 查看/proc/##PID/maps可以查看当前进程占用物理内存的地址。 给自己讲linux 2017-01-29 评论 1696 次浏览
第五十九讲——进程之间的关系 在linux系统上,所有的进程都是一个进程的子进程,这个进程是init。 由内核生成init进程,此外所有进程由init进程生成,进程也是由优先级关系的。 内核尽可能的将公平的按需资源分配给各个进程。 但是在这些进程当中,必然会有一些进程的优先级,或者要实现的功能紧急性是高于其他进程的,所以我们应当优先满足这类进程的资源需求。 linux中进程的优先级共分为140个(0-139) 进程优先级的数字越小,优先级越高。其中0-99是由内核调整的,100-139由用户控制。 一般来讲,优先级越高的进程就越先执行,当同级别的进程很多时,从众多同级别进程中挑选一个也是很耗费时间的。因此,在linux2.6内核中引入了一种独特的机制,无论同级别进程队列有多长,从中找到一个进程所消耗的时间是相同的。 在计算机的程序设计上,衡量一个和程序/算法,面对不同长度的队列它的性能如何有一个标准:O O(1):无论队列有多长,从中挑选一个的时间是一样的。 O(n):线性增长,队列越长消耗的时间越多。 O(log n): O(n^2) O(2^n) 代表的是,我们从队列中挑取一个数据所需时间随队列长度变化,曲线呈现出这种函数的形式。 一个进程的优先级高一般有两种特性: 一是获得更长的CPU运行时长。 二是更优先获得CPU运行的机会。 用户可调的优先级范围为100-139 每一个进程都有一个NICE值 nice:-20-19,分别对应nice中100-139 每一个进程的默认nice值为0. 普通用户只能够调大nice值,管理员不受限制。 我们可以按照用户的权限对进程的nice值进行调整 一 如果进程已经启动,使用renice更改程序的优先级nice值 renice # PID (-20 - 19) 二 我们还可以在程序启动时为进程指定nice值(启动时默认为0) nice -n # command(命令) (-20 - 19) 内核为了追踪进程,依靠进程ID,即PID,procec ID进程号 除了init进程,其它进程都有父进程。 /proc/目录下,以数字命名的目录,每一个目录对应一个进程,目录下保存了这个进程的所有相关属性信息。。每一个进程号都是唯一的,就算进程退出了,其它进程也不会占用该进程号。 在众多的进程当中,init的进程号永远为1. /proc是伪文件系统,关机状态下该目录下是没有任何文件的。 /proc/目录下以数字命名的目录对应的进程,目录下的文件是内核中参数的映射,让我们看起来是一个文件,都是与进程相关的属性。 #pstree 进程树查看,可以很清楚的分清楚子进程和父进程。 #ps:process state(进程状态),用于查看进程的相关信息的专用命令,这个命令有很多种使用风格: linux两大阵营:BSD、system V(罗马数字5) BSD风格,所有的选项都没有短横线。 system V风格:所有的选项都需要加短横线‘-’ #ps: -a 显示所有和终端有关的进程。 -u 显示进程是由哪个用户启动 -x 显示与终端无关的进程,用问号?表示与终端无关。 进程按照与终端相关与否分为两类: 跟终端相关的进程,通过命令启动的进程。 跟终端无关的进程,随内核启动的进程。 #ps ax PID(进程号) TTY(终端) STAT(进程状态) TIME(运行时长) COMMAND(命令) STAT(进程状态) D不可中断的睡眠 R运行或者就绪 S可中断的睡眠 T停止 Z僵死态 BSD风格 < 表示优先级高的进程 N 表示优先级低的进程 +前台进程组的进程(进程组:bash下的进程。前台,从命令行运行起来的。) l 多线程进程 s 会话进程首进程 ps aux |head(默认显示10行)BSD风格 USER(进程的有效用户,发起者) PID(进程号) %CPU(占用CPU时长同所运行时长的比值) %MEM(占用内存的百分比) VSZ(虚拟内存级) RSS(常驻内存级) TTY(关联终端) STAT(进程状态) START(启动时间) TIME(运行时长,真正占用CPU的时长) COMMAND(由哪个命令启动的进程,如果命令中加了中括号,表示这是一个内核进程) #ps –elF -A|-e显示所有进程 -l 长格式显示 -F 显示更多的更详细的内容 ps –el UID(用户ID) PID(进程号) PPID(子进程号) PRI(优先级) NI(nice值) SZ(size大小) -el通常和-F一块儿使用。 ps –elF RSS(常驻内存级) PSR(正运行在哪个CPU上) 常用的有ps –elF、ps –eF、ps –ef ps –o 可以指定显示的字段,怕是命令默认只显示前台进程。 #ps –axo pid,comm,ni 只显示ps –ax中PID、COMMAND、NI字段。 #pstree显示进程树 #pgrep,以grep的形式显示进程信息。 pgrep–U root bash以root身份运行的bash进程 -u euid -U UID 例如:user1执行了一个命令,而命令的属主是root,命令的发起者为user,是以root身份运行的,此时root就是euid,即有效ID #pidof 指定一个程序名找PID(进程号) ps显示的为命令执行那一刻的信息 我们还可以使用top命令动态查看,默认每5秒刷新一次,监控系统最好用的命令之一。 top命令下列表解释: 第一行:系统时间、运行时长、登录用户、平均负载(load avrage 过去一分钟,过去五分钟,过去十五分钟的平均队列长度,值越小,CPU负载越低) 第二行:TASKS(所有进程相关信息) ntotal(n个进程)1running,n-1 sleeping,0stopped,0zombie 第三行:CPU(s)CPU的负载情况,多核心CPU可能有多行 US(userspace,用户空间,用户进程所占用的百分比) SY(内核空间占用百分比) NI(调整nice值影响的比例值) ID(空闲百分比) WA(等待I/O 完成所占用的百分比) HI(硬件中断占用时间) SI(软件中断占用时间) ST(被偷走的时间) 内存空间 SWAP交换空间 top有许多的交互式的子命令: M根据驻留内存大小进行排序(默认为CPU使用百分比排序) P 根据CPU使用百分比排序 T 根据累计时间进行排序 l:是否显示平均负载和启动时间 t: 是否显示进程和CPU状态相关信息 m 是否显示内存相关信息 c:是否显示完整命令行信息 q:退出top命令 k:终止某个进程,通过进程号 给自己讲linux 2017-01-28 评论 1667 次浏览
除夕夜,为你守岁,我的影子 想写这么一段日记,却一直未曾动过笔。这个题目应该是高中的时候在脑海里的那么一个念想吧,兴许是没有合适的机会,从一三年拖到了三年后的今天。如果一四年不曾有过选择,这篇日记会早些日子出炉的吧?我带着这个题目,不,应该是这句话去践行了自己的想法。应该,也许就是这样了。 这个除夕夜,写下这些东西的我已满二十四周岁,一个放在六七十年代能撑起一片天的年纪,却只能在这个年代残喘并且迷茫着。很多的时候像是正坐在满桌佳肴的饭桌前,才低头吃上一口刚夹的菜,蓦地抬头只有杯盘狼藉的一切了。 前些日子匆匆翻阅了以前的日记,从初中到高中再到大学,字里行间都透露出俩字:孤独。且不管它是精神上的还是肉体上的。这让我想起小时候独自一人在没过头顶的芦苇丛里瞎逛,那感觉就像是站在自己的领地上巡视一样,并且内心热血沸腾。那时候六伏天坐在水渠旁的沙地上背对着太阳看着黝黑的影子,并用石头堆出自己的轮廓,太阳动一点,我就把石头跟着挪一点,晒得后背和头发发烫却依然乐此不疲,偶尔还能玩到影子拖得老长老长的时候。从那时起,我就开始了孤独的旅程罢,还好,有影子陪伴,虽然形单影只。可能从那时候起,我就渴望有一些朋友,那时候的我还是和小姑娘说句话都不好意思的年纪,那时候吹牛也无边无际,小伙伴们听得津津有味并信以为真,真有些佩服那个吹牛时不打草稿并且脸不红心不跳的自己了。后来不吹牛了,却不被相信了,也许是我的经历奇特了些,记得曾讲述大学下课后雨中漫步时,一陌生姑娘给我撑伞的事时,有人质疑我是不是在演偶像剧,也有人表面上相信背地里却肆意谈论并加以嘲讽,那时的我笑一笑,只要自己经历并且相信就好。我把自己的趣事分享给大家,让大家笑一笑,聊一聊,虽然有的时候显得并不有趣。再后来,我喜欢坐在烈日下面向太阳,那种毛孔刺痛的感觉令我清醒,偶尔看看影子,一样的轮廓,不一样的是,我在三维,他在二维,我坐在地上,他贴在地皮上。 二十四个春秋寒暑,走到哪里跟到哪里的,是我的影子,一起经历,一起折腾这副并不结实的身板,在空旷的地皮上略显孤单,这却是不太容易改变的现状。所以,我的影子,委屈你跟着我四处游荡了,这将继续下去并且不知道是否有尽头。二十四年,我头一次这么认认真真的守岁,正儿八经的一个人,没有联系任何人,没有发拜年祝福短信,当然,也不曾收到。按理说我这个年龄阶段不抽烟,拒绝喝酒,拒绝牌桌,极少游戏的小伙子几乎绝迹了,因为时常有人告诉我,我不适合干这,不适合干那,我只能笑一笑,回复很简单的几个字:是,有道理。我没有必要去反驳,表面上承认就好,每个人都有自己的想法,可能还会有一种信仰,不然就不会有千奇百怪的人生。而我,属于下了决定就死磕到底,不决定就和稀泥的主,我一直力图改变着,我不想看着影子随我的挥霍无度而颓圮,从而失去那一点的可观性。我不想让影子随我一起消沉,因为,这是我唯一的伙伴了,一个和我动作高度一致却不能言语的伙伴。所以不要问我在烈日下瞎逛什么,我高兴。 刚刚收到了血站的祝福短信,于凌晨两点四十一分。这件事还得从一六年十月份刚回来说起,十月一日到达巴中,看到这个熟悉又有点陌生的城市不知道能做些什么,徒步路过广场中心血站时突然觉得自己还是有用的。十月三号,血站放假。十月四日,专程献血,意外收获是一张移动五十元的充值卡和一罐纯牛奶,心情很好,这样做也许会有些作用呢?这算不算是一种社会担当,我不知道。不过这并不重要,我将持续下去,如果那个时候的我很健康。 为了写下这些文字,我于大年三十下午下午从老家奔了回来,虽然老妈强调了好几次在家里陪老太爷聊聊天,我依旧按自己的想法坐在这里写下了守岁语,如果今天不完成这个计划,我不知道什么时候才能完成,写东西这件事一拖就没有底了,趁着念头强烈一鼓作气完成。写东西不比追姑娘,几张纸、一支笔即可。 妄尘集 2017-01-28 评论 1669 次浏览
第五十八讲——什么是进程、线程 现在的操作系统都是由内核,和运行在内核之上的众多进程来实现。 启动起来的程序其实位于内存当中。简单基于物理内存来管理同时运行多个程序是非常不方便的,任何一个程序的BUG都有可能覆盖其他程序的数据,所以,为了避免这一情况出现,引入了内存地址的概念。内存地址由虚拟内存(线性内存)和物理内存的概念。 进程是逻辑上的概念。 内核在内部维护有一个数据结构(task structure任务结构)。 每一个进程的结构: PPID:副进程号 PID:进程号 NAME:名称 使用了多少内存页 内核会为每个进程保存它的数据结构,这个数据结构中保存了进程的终端信息,内核通过这个数据结构判断下一进程是谁,从哪儿开始(状态信息)。 对计算机来讲,只有CPU和内存。 CPU上一次只能执行一个程序,CPU划分时间片,内存划分为时间片,内存划分为页面,分配给多个程序。 CPU中有缓存、寄存器,会将终端程序的信息载入,当装在过程完成表示线程已经恢复,这是恢复现场的过程,终端断为保留现场。 在80286CPU以后就引入了线性地址空间(虚拟地址),以32位为例(最大支持4G内存空间2^32) CPU将除内核外的内存划分为许许多多的页面,这些页面为固定大小的存储单元,假设为4K。 当一个程序运行需要使用10K的时候,则需要向内核申请10K的内存空间,即三个4K页面(页框),这三个页框在物理上很有可能不是连续的,但是在程序自身看起来寺连续的,并且只有程序本身和内核运行在内存上。内存页面的信息保存在数据结构中,除了内核占用的空间,其余的空间都是这个进程所有,且这些空间都是连续的,但实际上这个程序是按需占用的。 这些页面的数据是存储在物理内存上的,有内核负责管理哪个页面上存了些什么数据,于是为了分清楚这些数据之间的关系,内核需要维护一张表,这个表中定义了每一个页面的数据和存储的具体页框的对应关系。每一个进程的进程地址空间由这样的几段组成: user stack 栈,通常用于存储本地变量(函数中的变量) 栈和共享库的可变空间 共享库,映射的是库页面的数据(对进程占用空间的有两种计算结果,一个是将共享库算进去,一个不。) runtime 堆内存(需要不停的动态申请内存空间),常用于载入文件 uninitialised(拼写可能有误) data(.bss)没能初始化的数据 program text(text)文本段(指令)只读段 forbidden 不允许进程使用,内核的腾挪空间。 VSZ:虚拟内存级,在逻辑上占用的大小(算上共享库的内存占用) RSS:常驻内存级(resident size)位于物理内存且不能被交换出去的。指令、变量等核心数据是不能被交换的。 在多核心的CPU上,我们可以让所有的进程平均分配到每个核心上,以提高工作效率。如果一个复杂的过程能够同时运行在多个核心上,那么执行的效率就会提高很多。 一般而言,一个进程只有一个执行流,从上而下是不动的,一步一步执行。 但是在某些并行编程模型下,可以实现将一个进程内部划分为多个小的执行实体,每个执行实体都有自己的指令加数据,这样就分成多个执行流了。根据功能的不同,这些执行流彼此之间是不能够互相交叉的,是比进程更小的单位,都可以被CPU单独执行,这个小单位我们称之为线程。 线程:thread 线程比进程更加节省空间,有些资源是可以共享的。 一是多进程模型 二是多线程模型:在内部生成线程,单进程多线程模型。 进程的状态: stoped,停止,不在被CPU调度,事假外力才能运行 read,就绪,在等待队列中 executing,正在运行中。 正在运行中需要其它内容转入睡眠状态: sleep:uninterruptible,不可中断的睡眠 sleep:interruptible,可中断的睡眠 为什么会睡眠? 当进程在执行的过程中突然需要打开一个文件,产生一个I/O请求,将硬盘中的数据载入内存,这个过程是需要消耗时间的,而对于CPU来讲就是浪费时间,I/O速度比CPU和内存慢得多,这时候进程会转入睡眠状态,让出CPU的使用权。 uninterrupible:不可中断的睡眠 当一个进程在CPU上运行时,因打开一个文件或者一个I/O操作而进入睡眠,并且在文件没有完全载入内存中时,就算再次唤醒该进程,也不会有执行动作,这类进程我们称为不可中断的睡眠。 interrupible:可中断的睡眠 一个进程执行完命令后,进入睡眠,等待下一次的唤醒,他不是等待外部I/O而睡眠的,这类进程我们称为可中断的睡眠,事实上用户的请求也是I/O,但是在此处不坐严格的区分。 zombie僵尸进程(僵死态) 指正常运行了,并且也结束了,但是其占用的内存空间就是不释放。 一个进程在CPU上运行结束后,内存应当会被释放,内核也会将逾期对应的那张维护的表删除(task structure) 给自己讲linux 2017-01-27 评论 1661 次浏览