操作系统
# 操作系统基础
# 什么是操作系统
- 操作系统是管理计算机硬件于软件资源的程序,是计算机的的基石。
- 操作系统本质上一个运行在计算机上的软件程序,用于管理计算机硬件和软件资源
- 操作系统屏蔽了硬件层的复杂性。
- 操作系统的内核是操作系统的核心部分,负责系统的内存管理、硬件设备的管理。
# 用户态和内核态
根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:
- **用户态:**用户态运行的进程可以直接读取用户程序的数据,拥有较低的权限。当应用程序需要执行某些需要特殊权限的操作,例如读写磁盘、网络通信等,就需要向操作系统发起系统调用请求,进入内核态。
- **内核态:**内核态运行的进程几乎可以访问计算机的任何资源包括系统的内存空间、设备、驱动程序等,不受限制,拥有非常高的权限。当操作系统接收到进程的系统调用请求时,就会从用户态切换到内核态,执行相应的系统调用,并将结果返回给进程,最后再从内核态切换回用户态。
内核态虽然拥有更高的权限,但是由于进入内核态需要付出较大成本开销(需要一系列的上下文切换和权限检查),因此尽量减少进入内核态的次数,来提高系统的性能和稳定性。
# 用户态和内核态切换方式
- 系统调用:用户态进程 主动 要求切换到内核态的一种方式,主要是为了使用内核态才能做的事情比如读取磁盘资源。
- 中断:当外围设备完成用户请求的操作后,会向 CPU 发出相应的中断信号,这时 CPU 会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。
- 异常:当 CPU 在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
# 系统调用
我们运行的程序基本都是运行在用户态,如果我们调用操作系统提供的系统态级别的子功能咋办呢?那就需要系统调用了!
也就是说我们运行的用户程序中,凡是与系统态级别的资源有关的操作(如文件管理、进程控制、内存管理等),都必须通过系统调用方式向操作系统提出服务请求,并由操作系统代为完成。
# 系统调用的过程
- 用户态的程序发起系统调用,因为系统调用中涉及一些特权指令(只能由操作系统内核态执行的指令),用户态程序权限不足,因此会中断执行,也就是 Trap(Trap 是一种中断)。
- 发生中断后,当前 CPU 执行的程序会中断,跳转到中断处理程序。内核程序开始执行,也就是开始处理系统调用。
- 内核处理完成后,主动触发 Trap,这样会再次发生中断,切换回用户态工作。
# 进程和线程
# 进程和线程的区别
从JVM角度去解释
# 进程的状态
- 创建状态:进程正在创建,尚未到就绪状态。
- 就绪状态:进程已处于准备运行状态,进程获得了除处理器之外的一切所需资源,一旦得到处理器资源,即可运行。
- 运行状态:进程正在处理器上上运行。
- 阻塞状态:又称为等待状态,进程正在等待某一事件而暂停运行如等待某资源为可用或等待 IO 操作完成。即使处理器空闲,该进程也不能运行。
- 结束状态:进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行。
# 进程间通信方式
- 匿名管道
- 有名管道
- 信号
- 消息队列
- 信号量
- 共享内存
- 套接字
# 线程间的同步方式
- 互斥量
- 信号量
- 事件
# 进程的调度算法
先到先服务(FCFS)调度算法 : 从就绪队列中选择一个最先进入该队列的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
短作业优先(SJF)的调度算法 : 从就绪队列中选出一个估计运行时间最短的进程为之分配资源,使它立即执行并一直执行到完成或发生某事件而被阻塞放弃占用 CPU 时再重新调度。
时间片轮转调度算法 : 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称 RR(Round robin)调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
多级反馈队列调度算法 :前面介绍的几种进程调度的算法都有一定的局限性。如短进程优先的调度算法,仅照顾了短进程而忽略了长进程 。多级反馈队列调度算法既能使高优先级的作业得到响应又能使短作业(进程)迅速完成。,因而它是目前被公认的一种较好的进程调度算法,UNIX 操作系统采取的便是这种调度算法。
优先级调度 : 为每个流程分配优先级,首先执行具有最高优先级的进程,依此类推。具有相同优先级的进程以 FCFS 方式执行。可以根据内存要求,时间要求或任何其他资源要求来确定优先级。
# 死锁
# 什么是死锁
死锁描述的是这样一种情况:多个进程/线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于进程/线程被无限期地阻塞,因此程序不可能正常终止。
# 死锁的四个必要条件
互斥:资源必须处于非共享模式,即一次只有一个进程可以使用。如果另一进程申请该资源,那么必须等待直到该资源被释放为止。
占有并等待:一个进程至少应该占有一个资源,并等待另一资源,而该资源被其他进程所占有。
非抢占:资源不能被抢占。只能在持有资源的进程完成任务后,该资源才会被释放。
循环等待:有一组等待进程
{P0, P1,..., Pn}
,P0
等待的资源被P1
占有,P1
等待的资源被P2
占有,......,Pn-1
等待的资源被Pn
占有,Pn
等待的资源被P0
占有
# 解决死锁的方法
预防 是采用某种策略,限制并发进程对资源的请求,从而使得死锁的必要条件在系统执行的任何时间上都不满足。
避免则是系统在分配资源时,根据资源的使用情况提前做出预测,从而避免死锁的发生
检测是指系统设有专门的机构,当死锁发生时,该机构能够检测死锁的发生,并精确地确定与死锁有关的进程和资源。
解除 是与检测相配套的一种措施,用于将进程从死锁状态下解脱出来。
# 内存管理
# 内存管理基础
操作系统的内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情。
# 内存管理机制
简单分为连续分配管理方式和非连续分配管理方式这两种。连续分配管理方式是指为一个用户程序分配一个连续的内存空间,常见的如块式管理 。同样地,非连续分配管理方式允许一个程序使用的内存分布在离散或者说不相邻的内存中,常见的如页式管理和段式管理。
连续分配管理方式
- 块式管理: 远古时代的计算机操作系统的内存管理方式。将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,我们称之为碎片。
非连续分配管理方式
页式管理 :把主存分为大小相等且固定的一页一页的形式,页较小,相比于块式管理的划分粒度更小,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址。
段式管理 : 页式管理虽然提高了内存利用率,但是页式管理其中的页并无任何实际意义。 段式管理把主存分为一段段的,段是有实际意义的,每个段定义了一组逻辑信息,例如,有主程序段 MAIN、子程序段 X、数据段 D 及栈段 S 等。 段式管理通过段表对应逻辑地址和物理地址。
段页式管理机制 :段页式管理机制结合了段式管理和页式管理的优点。简单来说段页式管理机制就是把主存先分成若干段,每个段又分成若干页,也就是说 段页式管理机制 中段与段之间以及段的内部的都是离散的。
# 分页机制和分段机制的共同点和区别
共同点
- 分页机制和分段机制都是为了提高内存利用率,减少内存碎片。
- 页和段都是离散存储的,两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
区别
- 页的大小是固定的,由操作系统决定,而段的大小不固定,取决于我们当前运行的程序。
- 分页仅仅是为了满足操作系统内存管理的需求,而段是逻辑信息的单位,在程序中可以体现为代码段,数据段,能够更好满足用户的需要。
# CPU寻址(虚拟地址)
现代处理器使用的是一种为虚拟寻址(Virtual Addressing) 的寻址方式。使用虚拟寻址,CPU 需要将虚拟地址翻译成物理地址,这样才能访问到真实的物理内存。
为什么要有虚拟地址
没有虚拟地址空间的时候,程序直接访问和操作都是物理内存,这样存在一些问题:
- 用户程序可以访问任意内存,寻址内存的每个字节,这样就很容易(有意或者无意)破坏操作系统,造成操作系统崩溃。
- 想要同时运行多个程序特别困难,比如你想同时运行一个微信和一个 QQ 音乐都不行。为什么呢?举个简单的例子:微信在运行的时候给内存地址 1xxx 赋值后,QQ 音乐也同样给内存地址 1xxx 赋值,那么 QQ 音乐对内存的赋值就会覆盖微信之前所赋的值,这就造成微信这个程序会崩溃。
如果直接把物理地址暴露出来的话,会对操作系统造成很多困难。
通过虚拟地址访问内存有以下优势:
程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为 4 KB)保存到磁盘文件。数据或代码页会根据需要在物理内存与磁盘之间移动。
不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。
# 虚拟内存
虚拟内存 的存在,通过 虚拟内存 可以让程序拥有超过系统物理内存大小的可用内存空间。
另外,虚拟内存为每个进程提供了一个一致的、私有的地址空间,它让每个进程产生了一种自己在独享主存的错觉(每个进程拥有一片连续完整的内存空间)。这样会更加有效地管理内存并减少出错。
# Linux
# 发行版本
- 商业公司维护的发行版本,以著名的 Red Hat 为代表,比较典型的有 CentOS 。
- 社区组织维护的发行版本,以 Debian 为代表,比较典型的有 Ubuntu、Debian。
平时学习用的centos
# 目录结构
目录说明
/bin: 存放二进制可执行文件(ls、cat、mkdir 等),常用命令一般都在这里;
/etc: 存放系统管理和配置文件;
/home: 存放所有用户文件的根目录,是用户主目录的基点,比如用户 user 的主目录就是/home/user,可以用~user 表示;
/usr : 用于存放系统应用程序;
/opt: 额外安装的可选应用程序包所放置的位置。一般情况下,我们可以把 tomcat 等都安装到这里;
/proc: 虚拟文件系统目录,是系统内存的映射。可直接访问这个目录来获取系统信息;
/root: 超级用户(系统管理员)的主目录(特权阶级^o^);
/sbin: 存放二进制可执行文件,只有 root 才能访问。这里存放的是系统管理员使用的系统级别的管理命令和程序。如 ifconfig 等;
/dev: 用于存放设备文件;
/mnt: 系统管理员安装临时文件系统的安装点,系统提供这个目录是让用户临时挂载其他的文件系统;
/boot: 存放用于系统引导时使用的各种文件;
/lib : 存放着和系统运行相关的库文件 ;
/tmp: 用于存放各种临时文件,是公用的临时文件存储点;
/var: 用于存放运行时需要改变数据的文件,也是某些大文件的溢出区,比方说各种服务的日志文件(系统启动日志等。)等;
/lost+found: 这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows 下叫什么.chk)就在这里。
# Linux常见命令
目录命令
cd
mkdir
ls
mv:移动
cp:拷贝
文件命令
- touch:新增
cat/more/less/tail 文件名称
:文件的查看(查) 。命令tail -f 文件
可以对某个文件进行动态监控,例如 tomcat 的日志文件, 会随着程序的运行,日志会变化,可以使用tail -f catalina-2016-11-11.log
监控 文 件的变化 。- vim
- rm -rf
权限命令
文件的类型:
- d: 代表目录
- -: 代表文件
- l: 代表软链接(可以认为是 window 中的快捷方式)
Linux 中权限分为以下几种:
- r:代表权限是可读,r 也可以用数字 4 表示
- w:代表权限是可写,w 也可以用数字 2 表示
- x:代表权限是可执行,x 也可以用数字 1 表示
chmod u=rwx,g=rw,o=r aaa.txt
或者 chmod 764 aaa.txt
- 数据拥有者:7 = r + w + x (4 + 2 + 1)
- 数据组: 6 = r + w (4 + 2)
- 其他用户:4 = r
# Linux的IO模型
- 同步模型(synchronous IO)
- 阻塞IO(bloking IO)
- 非阻塞IO(non-blocking IO)
- 多路复用IO(multiplexing IO)
- 信号驱动式IO(signal-driven IO)
- 异步IO(asynchronous IO)
# GREP命令的原理
grep全称是Global (opens new window) search regular expression and print out the line,全局搜索正则表达式,简称grep,它能根据用户指定的文本模式对目标文件进行逐行搜索,并打印(搜索,删除,替换)能够被模式匹配的行
# 查看日志的几种方式
1、tail
命令格式
命令格式: tail[必要参数][选择参数][文件] -f 循环读取 -q 不显示处理信息 -v 显示详细的处理信息 -c<数目> 显示的字节数 -n<行数> 显示行数 -q, --quiet, --silent 从不输出给出文件名的首部 -s, --sleep-interval=S 与-f合用,表示在每次反复的间隔休眠S秒
用法
tail -n 10 test.log ## 查询日志尾部最后10行的日志; tail -n +10 test.log ## 查询10行之后的所有日志; tail -fn 1000 test.log ## 循环实时查看最后1000行记录(最常用的) ## 可配合grep使用 tail -fn 1000 test.log | grep '关键字' ## 如果一次性查询的数据量太大,可以进行翻页查看 tail -n 4000 test.log |more -1000 ## 可以进行多屏显示(ctrl + f 或者 空格键可以快捷键) ## 把test.txt文件扔进垃圾箱,赋空值test.txt cat /dev/null > /etc/test.txt
2、head
head -n 10 test.log ## 查询日志文件中的头10行日志;
head -n -10 test.log ## 查询日志文件除了最后10行的其他所有日志;
3、cat
## 一次显示整个文件
$ cat filename
## 创建一个文件
$ cat > filename
## 将几个文件合并为一个文件
$ cat file1 file2 > file ## 只能创建新文件,不能编辑已有文件.
## 将一个日志文件的内容追加到另外一个
$ cat -n textfile1 >> textfile2
## 清空一个日志文件
$ cat : >textfile2
## 注意:
## > 是创建,将两个或多个文件连接到另一个新文件;
## >> 是追加,运算符将输出附加到指定文件,或者如果它不存在则创建指定文件。
# select、poll、epoll
现在我是领导,下面我有一堆员工,现在我想要查看这些人是否完成任务:
select:只能管理1024个员工,且每次对于没有完成进度的员工要不停去询问。
poll:管理能力更强,能够管理更多员工。
epoll:除了管理能力更强,管理方式变化了,相当于他通知这些员工一遍,就不会多次去询问了,然后让这些员工做完事情了,过来通知一下。