1.Linux中根目录下的目录有哪些?
bin目录
存放二进制文件,一般是常用的一些指令
sbin目录
su管理员才能访问的二进制文件,一般是得用su才能使用的指令
home目录
家目录,存放的是除了root用户以外其他用户的家目录
etc目录
存放配置文件,cat /etc/passwd密码配置
dev目录
设备目录,存放外设文件
usr目录
存放用户自己安装的软件
tmp目录
存放临时文件
var目录
存放日志文件
proc目录
存放进程,该目录不占用磁盘空间,在内存中
mnt目录
当外设需要挂在的时候,就需要挂在到mnt目录下
run目录
系统开机产生的信息
2.Linux中绝对路径和相对路径的区别?
绝对路径必须是从根目录开始的,比如/home/syc/cppDir/Server.c
相对路径是从当前路径开始的,假设当前路径是/home/syc/cppDir,那么上面的路径就可以表示位./Server.c
3.Linux中常见的文件类型有哪些?
-(普通文件)
存文本文件(ASCALL码编码的等)、二进制文件
d(目录文件)
dirctory目录
c(字符设备)
鼠标、键盘等外设
b(块设备)
磁盘等提供系统随机存取的接口设备
l(软连接文件)
相当于Windows下的快捷方式
p(管道文件)
用于进程间通信,pipe、fifo匿名管道和命名管道
s(套接字文件)
用于网络通信
4.Linux下你常用的指令有哪些?
ls
ls -alh
列出当前路径下所有文件以列表的形式并且高可读
pwd
print working path
打印当前工作路径
cd
change dirctory
切换路径
cd ~ //切换到家目录 cd .. //切换上一级目录 cd / //切换到根目录
du
disk usages
当前路径磁盘的使用情况
cp
文件
cp ./a.txt ~/pyDir/b.txt
// 把当前路径下的a.txt文件 复制到 pyDir目录下并改名为b.txt
目录
需要加-r递归选项
cp -r ./a ~/pyDir/b
// 把当前目录下的a文件夹 移动到 pyDir目录下并改名为b
mkdir
创建文件夹
touch
它本来的作用是修改文件或者目录的时间属性,但如果不存在文件则创建文件
mv
剪切和改名功能
rm
删除文件或者文件夹,rm文件夹要加-rf选项,就是递归强制删除
cat
查看文件内容,输出到终端中
tail
从后面查看,一般用于查看日志文件
head
从前面查看
find
find ./ -name "*.c"
find ./ -type l
fidn ./ -maxdepth 1 -name "*.c"
find ./ -size +10M -size -50M
wc
word count
统计单词数量
wc -lwc a.txt
> 和 >>
覆盖重定向和追加重定向
ls -l > a.txt //覆盖重定向
ls -l >> a.txt //追加重定向
|
管道符
指令1 | 指令2,指令1的输出作为指令2的输入
ls / | wc -lwc
//ls的输出作为wc指令的输入,统计它的行数、单词数,字节数
tar
压缩指令、解压指令
tar abc.tar.gz -gcvf a.txt b.txt c.txt
//打包a.txt b.txt c.txt 并压缩到压缩文件abc.tar.gz中
tar -zxvf abc.tar.gz
//解压abc.tar.gz文件到当前路径
man
man手册,可以查看系统调用函数和库函数的函数原型
clear + l
清屏
ctrl + alt + t
打开终端
ctrl + shift + +
放大终端
CTRL + -
缩小终端
reboot
重启虚拟机
shutdown
关闭虚拟机
5.谈一谈你对Linux文件系统的了解?
文件系统分为三个区块
inode模块
inode中主要记录文件的属性(创建时间、大小)和文件内容所在的block
一个文件只有一个inode,但是一个inode却可以对应多个block,这是因为文件内容可能很大,所有需要多个block去存储,但是inode里面存储的是文件的属性和对应的block,一般一个inode就能够存储
block模块
记录的是文件中的具体内容
superblock模块
superblock里面记录的是文件系统的整体信息,例如inode的总量、使用量、剩余量等等
文件的文件名不在它对应的inode里面存储,而是在它的上一级目录存储
6.什么是硬链接?
硬链接就是给文件起了个别名,多个文件名指向同一个inode,这种情况就是硬链接。如图
a目录下的1.c和b目录下的2.c都指向同一个inode3,所以1.c和2.c建立了硬链接
7.什么是软连接?
软连接文件里面存储的是要链接链接文件的路径,最后存储绝对路径
8.什么是操作系统?
操作系统是软件硬件之间起桥梁作用的一个庞大的程序,简单点来说就是在硬件的外层套了一层软件,这层软件可以帮助用户去管理硬件资源,而不需要直接去操作硬件。
9.如何把输入变成非阻塞?
重新打开输入输出文件,以非阻塞的形式打开
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char* argv[]){char buf[1024] = {'\0'};int fd = open("/dev/fd/0", O_RDWR | O_NONBLOCK);int readCount = read(fd, buf, sizeof(buf));write(fd, buf, readCount);return 0;
}
10.Linux中创建有关文件IO的函数有哪些?
open函数
打开文件
close函数
关闭文件
read函数
把文件中的数据读到缓冲区
write函数
把缓冲区的数据写到文件中
lseek函数
设置文件偏移量
获取文件偏移量
扩容
fcntl函数
获取文件的访问模式
设置文件的访问模式
stat函数
获取文件的属性
perror函数
打印报错信息
dup、dup2函数
赋值文件描述符
11.父子进程
不光是代码复制过来了,数据段和堆栈都复制了一份
并且栈区的虚拟内存地址是一样的,但是你修改父进程的栈区内容,子进程不受影响,因为虚拟地址映射的磁盘空间是不一样的
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<fcntl.h>
#include<sys/wait.h>
#include<stdlib.h>
int main(int argc, char* argv[])
{char *ptr = (char*)malloc(100);memset(ptr, '\0', 100);memcpy(ptr, "hello", 6);int pid = fork();if(pid == 0){memcpy(ptr, "world", 6);printf("child, ptr = %s, dz = %p\n", ptr, ptr);}else{sleep(1);printf("parent, ptr = %s, dz = %p\n", ptr, ptr); }return 0;
}
child, ptr = world, dz = 0x55fbf47c8260
parent, ptr = hello, dz = 0x55fbf47c8260
12.进程于线程之间的区别和联系?
什么是进程?
线程是运行起来的程序,它是操作系统进行资源分配的基本单位
什么是线程?
线程你可以理解为是进程下的子任务,它是操作系统进行CPU调度的基本单位
进程的优缺点
缺点
不同进程时间数据的独立的,导致通信困难,操作系统提供了一些用于进程通信的方式,有管道、内存映射、消息队列等。
由于是资源分配的基本单位,代价高
优点
但是数据的独立也不全是缺点,因为之间不会互相影响,也不涉及同步的概念(同步指的是不同的线程在访问同一块资源的时候,出现的错误,为了防止这种错误,不同线程之间做了一种协同步调)
线程的优缺点
缺点
不同线程之间数据是共享中,导致不同线程在访问同一块资源的时候出现错误,为了防止这种错误,出现了同步的概念,就是双方做的一种约定,Linux提供的同步的方式有互斥锁+条件变量、读写锁、信号量(PV操作)
优点
通信简单,因为资源共享
创建代价低,因为多个线程共享同一个进程资源
联系
进程与线程之间是一对多的关系,一个进程下有多个线程子任务,换句话来说一个进程可能有多个线程,但是一个线程只能存在于一个进程中
13.Linux理论上可以创建多少个进程?一个进程可以创建多少个线程,和什么有关?
最大创建的进程数默认是32768,但是可以通过修改配置文件来重置最大进程数
cat /proc/sys/kernel/pid_max
32768ulimit -u 655351
sysctl -w kernel.pid_max=655351·
最大线程数取决于操作系统分配的线程栈的大小,以及操作系统是32位还是64位
通常是32位下是300多个
【操作系统】进程通信的几种方式_操作系统进程通讯的几种主要方式-CSDN博客
14.单工通信、半双工通信、全双工通信的区别
单工通信指的是只能由一端发给另外一端
最常见的遥控器,只能遥控器控制空调,不能空调控制遥控器
半双工通信指的是在同一时刻,只能一端发给另外一端,但是究竟是哪一段发的,没有限制
对讲机
全双工指的是在同一时刻,俩段可以互相通信
视频、打电话
15.什么是内核缓冲区?
内核缓冲区是操作系统内核中一个用于临时数据存储的内存空间
16.进程间通信方式有哪些?
由于不同进程之间的数据独立性,导致通信困难,所有需要借助一个第三方资源,不同进程之间操作这个第三方资源,从而实现进程间通信,由于这个第三方资源可以由操作系统的不同模块提供,所有有了不同的通信方式,操作系统用于进程通信的方式有管道、消息队列、mmap内存映射、信号、套接字
管道
管道的特性有哪些?
管道的本质是一个内存文件,或者说是OS内核的缓冲区,不不占用磁盘的空间。
由于管道之后一个读端和一个写端,所以它只能单向通信也就是半双工通信。单向通信有好处也有坏处,好处是不用去考虑进程的同步问题,坏处是无法实现互发消息,所以必须使用俩个管道才能实现消息的互发
当管道中的数据被读走之后,OS会自动把该数据从管道中清楚,就像一个循环队列一样
匿名管道
匿名管道一般用于父子进程的通信,因为只有父子进程之间才能共享同一个文件描述符。创建匿名管道的方式是pipe函数,他会得到一个读端,一个写端。
命名管道
命名管道通常用于没有血缘关系的进程之间的通信,创建方法是mkfifo,该文件是不占用磁盘空间的,在内核缓冲区中
内存映射
内存映射就是让不同进程实现内存的共享,从而实现进程的通信,具体方式是让ps1做共享的那段内存映射到磁盘中,ps2做共享的那段内存同样映射到磁盘的那个位置。
内存映射也分位匿名映射和命名映射
消息队列
消息队列就是内核在缓冲区中维护的一个消息链表,可以实现一条消息一条消息的通信,每个链表中的结点由指针域指向下一节点、msg、len、优先级
套接字
套接字是用于网络中不同主机进程通信的
信号
Linux 进程间通信 信号(signal) - 管理员D - 博客园 (cnblogs.com)
信号以一种异步通信方式,无需知道对方进程的状态,可以直接由一个进程发给另外一个进程。
例如你调用kill函数的时候,当前进程会给你要杀死的进程发送一个信号,如果要杀死的进程正在执行,则直接杀死,若要杀死的进程没有处于执行状态,则该信号会由内核保存起来,知道该进程恢复执行传递给它。
信号量
信号量并不是一种用于传输数据的进程间通信方式,它是为了解决不同进程在访问同一块资源的时候,产生的不同步问题。因为进程间通信的本质就是不同进程去访问同一块第三方资源,信号量就是一种进程间的同步机制
信号量是通过PV操作来保证同步的,当信号量的值位0的时候,不允许访问该资源。P操作sem_wait操作用于信号量减一,sem_post操作用于信号量加一
17.进程调度算法有哪些?
进程有三个状态,就绪、运行和阻塞,就绪状态的进程要想持有CPU到运行态,就需要进程调度算法
进程调度算法有FCFS(先来先服务算法)、SJF(短作业优先算法)、HHRT(高响应比调度算法)、时间片轮转算法等
FCFS
先来先服务算法
处于就绪队列中的作业,先来的先获得CPU的使用权,先来先服务算法属于非抢占式算法。非抢占式的意思就是当一个作业完全执行完之后,才能执行另外一个作业,中间不能中断
SJF
短作业优先算法
它分为抢占式和非抢占式
非抢占式
在就绪队列中选择一个执行时间最短的作业,获得CPU的使用权。中间即使有一个比他服务时间还短的信号的作业,也不能中断
抢占式
在就绪队列中选择一个服务时间最短的作业,获得CPU的使用权,如果中间有一个新作业到就绪队列中且服务时间比当前作业的剩余服务时间短,则会中断发生抢占执行该新作业
HHRF
高响应比优先算法
相应比 = (等待时间 + 服务时间)/ (服务时间)
等待时间就是作业未获得CPU使用权之前,在就绪队列中的时间
服务时间就是该作业持有CPU的时间
响应比高的优先执行
时间片轮转算法
讲CPU处理的事件分为若干个时间片,进程安装先后顺序排序,队首的先消耗一个时间片,如果还有剩余服务事件,就把该作业放到队尾,等待下一个事件片继续消耗。
18.执行一个进程需要哪些工作?
进程是运行起来的程序,首先你得有可执行程序,一个变成语言需要经过预处理、编译、汇编、链接这四个步骤,才能变成可执行程序(一组指令的集合)。要想程序编程进程还需要一个装入的过程,就是把模块装入内存之中
19.为什么要使用虚拟地址?
虚拟地址为每个进程提供了独立的地址空间,防止一个进程访问或者修改其他进程的内存。
虚拟内存允许操作系统将暂时不用的内存页面交换到磁盘上,从而扩展了可用内存的容量。
可以实现共享内存,不同进程之间正常映射的物理地址是不一样的,但是使用共享内存的方式可以让不同的进程访问同一块内存,实现进程间通信
64位系统可以提供巨大的虚拟地址空间,远大于实际的物理内存,这为应用程序提供了更大的灵活性
保证了进程的独立性
因为每个进程都有自己独立的虚拟内存,并且认为自己拥有一块连续的内存空间,至于怎么去映射的那是操作系统的事情
进行逻辑分段,方便管理
虚拟地址把物理内存按逻辑进行了分段处理,例如栈段、堆段、数据段、代码段。方便管理
提高了内存的利用率
当内存不够用的时候,可以通过SWAP机制,换入换出到磁盘,提高内存的利用率
支持内存共享
mmap,虚拟地址映射到磁盘
20.说一下操作系统的内存管理?
操作系统的内存管理方式可以分为三种,第一种是分段式管理、第二种是分页式管理、第三种是段页式管理。
分段式存储管理方式
首先说一下分段管理,我们都知道操作系统的内存地址分为虚拟地址和物理地址,虚拟地址是为了在多进程环境下,进程于进程之间的内存地址互不影响。分段中,虚拟地址通过段表映射到物理地址上,虚拟地址可以划分出段号和段内偏移量,通过段号可以在段表中找到基地址 + 段内偏移量就可以得到真正的物理地址。这就是分段式管理方式,的内存映射机制。但是在分段管理方式中,存在外碎片问题和内存交换效率低等问题。存在外碎片的原因是段与段之间由于内存的释放,而产生了一个没有申请的外碎片,解决方法就是内存交换,磁盘中专门预留了一块区域做内存交换。
分页式存储管理方式
虚拟地址可以划分出虚拟页的页号和页内偏移量,通过虚拟页的页号在页表中找到物理页的页号,然后找到物理页的基地址 + 页内偏移量得到内存物理地址。在分页管理方式中,页与页之间的大小式相等的,也就是说内存被均分位了若干个页,但是这种方式会产生内碎片问题,如果我想申请一个5MB,但是页的大小是10MB,你必须申请的是一个完整页的大小,所以会有5MB的内碎片产生。
单个页表会造成页表过大的问题,一般使用到是多级页表,接了解决空间上的问题。
段页式存储管理方式
先把内存分为有逻辑意义的段,然后再把每个段划分位多个页。那么虚拟地址可以划分为短号、页号、页内偏移量。先通过段号找到不同段的页表,然后在通过页表找到物理页,然后再找到物理页的偏移量,然后再加上页内偏移量得到物理地址
内存分区
21.实现一个LRU算法?
LRU算法是在分页内存管理中为了提高内存的使用效率,把哪些最近最少使用的页面置换出去。
具体过程,假设内存中只能容纳3个页,那么按照7 0 1 2 0 3 0 4 的次序去访问页。
它的实现原理是哈希链表 + 双向链表
哈希链表主要作用是实现O(1)快速判断出入链表中的元素是否存在,并且可以快速定位它在链表中的位置
双向链表主要实现O(1)的插入和删除操作
22.死锁产生的必要条件有哪些?
互斥条件:一个资源只能被一个进程或者线程使用
持有并等待条件:一个进程持有锁并等待另外一个进程解锁
环路等待条件:A持有1锁等待2解锁,B持有2锁等待1解锁
不可剥夺条件:如果没有解锁必须一直等待
产生的原因:
锁的分配顺序不对,产生了环路等待条件
23.死锁如何恢复?
重新启动
终止于死锁有关的进程
资源剥夺
进程回退
让参与死锁的进程回退到没有发生死锁的那个状态
24.什么是饥饿?
饥饿是指由于资源分配不公,一个进程或者线程迟迟不发获得资源的现象
例如读写锁的时候,读优先,就会造成写进程迟迟无法访问资源
例如进程调度的实话,使用短作业优先算法,那么服务事件长的进程就会产生饥饿现象
25.如何手写一个互斥锁?
实现互斥锁mutex,实际上就是去实现它的lock方法和unlock方法。先定义个全局变量mtx,mtx为0表示没有上锁,mtx为1表示上锁
static int mtx = 0;void lock(){while(mtx == 1);mtx = 1;
}void unlock(){mtx = 0;
}
26.什么时候使用多进程,什么时候使用多线程?
什么是进程?
线程是运行起来的程序,它是操作系统进行资源分配的基本单位
什么是线程?
线程你可以理解为是进程下的子任务,它是操作系统进行CPU调度的基本单位
进程的优缺点
缺点
不同进程时间数据的独立的,导致通信困难,操作系统提供了一些用于进程通信的方式,有管道、内存映射、消息队列等。
由于是资源分配的基本单位,代价高
优点
但是数据的独立也不全是缺点,因为之间不会互相影响,也不涉及同步的概念(同步指的是不同的线程在访问同一块资源的时候,出现的错误,为了防止这种错误,不同线程之间做了一种协同步调)
线程的优缺点
缺点
不同线程之间数据是共享中,导致不同线程在访问同一块资源的时候出现错误,为了防止这种错误,出现了同步的概念,就是双方做的一种约定,Linux提供的同步的方式有互斥锁+条件变量、读写锁、信号量(PV操作)
优点
通信简单,因为资源共享
创建代价低,因为多个线程共享同一个进程资源
联系
进程与线程之间是一对多的关系,一个进程下有多个线程子任务,换句话来说一个进程可能有多个线程,但是一个线程只能存在于一个进程中
27.孤儿进程和僵尸进程分别是什么?如何形成的?
孤儿进程
子进程还在运行,但是父进程结束,那么子进程在这一阶段就会变成孤儿进程,但是这个阶段不会持续太久,OS会用init进程去领养孤儿进程
僵尸进程
子进程结束,但是父进程没有调用wait或者是waitpid回收剩余资源,导致子进程的PCB等残留数据留在OS中,这些子进程就是僵尸进程
28.说一下PCB是什么?
PCB是进程控制块,是用来表示进程状态的一个数据结构。
PCB中包含:pid、进程的状态、进程调度的信息等等
29.说一下进程的地址空间
从高到低依次是栈、堆、数据段(已初始化的DATA段和未初始化的BSS段)、代码段
30.内核空间和用户空间是怎么区分的?
内核空间时用来存放内核代码和数据的,而进程的用户空间存放的时用户的代码和数据,具体有什么:栈、堆、数据段(BSS段和DATA段)、代码段
31.多线程是如果同步的?
互斥锁 + 条件变量
具体使用流程是先初始化一个互斥变量,然后给要共享的资源前面加锁,访问完了之后解锁。
pthread_mutex_init();
pthread_mutex_lock();
pthread_mutex_unlock();
pthread_mutex_trylock();//用来避免死锁,破坏第四个不可剥夺条件
pthread_mutex_destory();;
读写锁
当读多写少的时候使用,因为读与读之间不会造成错误,读写锁在读与读之间不会阻塞,写独占,读共享
pthread_rwlock_wrlock();
pthread_rwlock_rdlock();
pthread_rwlock_unlock();
pthread_rwlock_init();
pthread_rwlock_destory();
读写锁有读优先还是写优先的问题,比如现在你的写进程正在持有CPU,由于读写锁是写独占、读共享的,所以当写进程执行完之后,如果有来个进程正在等待分别是写进程和读进程,那么此时就涉及到了读优先还是写有限的问题。如果处理不当的话可能会造成饥饿现象
信号量(PV操作)
P操作sem_wait(),会对信号量-1
V操作sem_post(),会对信号量+1
如果信号量为0则会阻塞
32.同一个进程内的线程会共享什么资源?
栈空间不同共享,线程函数的占空间是自己独有的
堆空间共享
数据段的全局变量共享
该进程的地址空间
33.一般情况下Linux/Windows平台下栈空间的大小是多少?
Linux:8MB
Windows:1MB
34.虚拟内存
每个进程都有自己独立的虚拟地址,不同进程之间无法访问对方的虚拟地址,所有保证了进程的独立性。
但虚拟地址毕竟是虚拟的,需要进程映射才能找到物理地址,从而访问资源。
这个映射因为内存管理的方法的不同,映射方式也不一样。在分段式内存管理、分页式内存管理和段页式内存管理中都不同。
分段式采用页表映射、分页式采用页表映射、段页式先用段表再页表映射。
虚拟内存的大小一般都大于物理内存的大小,比如在一个32位的操作系统中,内存的大小位4GB,但是可能一个进程的大小就4GB了,那么内存是如何处理的那,只要当使用到进程中的那段内容的时候,资源才会被调入到内存之中。
(*)35.服务器高并发的解决方案有哪些?
应用数据与静态资源分离
采用缓存机制
集群和分布式
反向代理
36.说一说Linux中的Swap机制
什么是Swap机制?
swap机制就是一个换入和换出的过程
换出指的是把内存中的数据存储到磁盘中,做一个临时的存储,然后释放该内存空间
换入zhide是把磁盘中的数据导入内存中
什么时候触发Swap?
物理内存不够用的时候
当物理内存不够用的时候(需要的物理内存大于可用物理内存),操作系统会把一些很长时间没有使用过的内存页换出到磁盘中,然后释放该内存,这样就会提高可使用物理内存的空间。
直接内存回收时同步的过程,会阻塞当前申请内存的进程
内存闲置的时候
操作系统专门维护了一个Kswap进程(后台守护进程),其作用时专门回收闲置内存(把限制内存换出到磁盘中,然后释放该内存空间)。一个进程在刚启动的时候往往会消耗大量的内存,并且在启动之后不会使用。这些内存就属于闲置内存,Kswap回收他们。再或者是当可用的内存低于一个水平值的时候,Kswap进程也会回收空闲内存,保证系统中其他进程可以申请到空间。
Kswap内存回收是异步的过程,不会则色当前申请内存的进程
如何开启和关闭swap机制?
开启
sudo swapon -a
关闭
sudo swapoff -a
Swap机制会提高内存的大小吗?
这是肯定不会是,不是说你没使用swap之前内存大小是4GB,使用了之后内存大小就变成了8GB了
但是开启swap机制的确可以提高内存的使用效率
比如你内存的大小是4GB,让你运行一个8GB的内存,如果开启了swap就是可行的。
不是说你的内存大小提高到了8GB了,而是这8GB的内存都在你真是的物理内存中存在过了。
37.4GB物理内存的机器上申请8GB内存会怎么样?
首先你的操作系统是32位还是64位,其次malloc申请的是虚拟内存不是物理内存,只要当应用程序访问这块虚拟内存的时候,操作系统才会去映射物理内存。所以如果你只是申请而不去访问这块虚拟内存的话,是不会映射的。
如果是32位的话,它的虚拟内存大小是4GB(1G内核 + 3G用户),而你要申请8GB肯定是会报错的。
如果是64位的话,它的虚拟内存大小是128TB的内核 + 128TB的用户,申请8GB的虚拟内存肯定可以
往大了说,如果你只是申请内存不去访问的话,你申请128TB都没问题,但是前提你得开启swap机制,因为128TB的虚拟内存需要一些物理内存去存储它的一写状态信息,可能大于4GB。如果开启了swap机制还失败的话,有可能是Linux中的overcommit_memory参数的问题,把它的默认值调节位1就可以了,1表示我不关心,对内存来者不拒
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>#define SIZE 1024*1024*1024int main(int argc, const char *argv[])
{char* addr[131070];for(int i = 0; i < 131070; i++){addr[i] = (char*)malloc(SIZE);if(addr[i] == NULL){perror("执行malloc错误");return -1;}printf("主线程调用%d次malloc函数后, 申请1GB大小的内存, 起始地址为:0X%p\n", i + 1, addr[i]);}// getchar();return 0;
}
但是如果你想访问你申请的虚拟内存空间,那么4GB的物理内存运行8GB的进程可能会产生问题,如果你不开启swap机制。
当访问虚拟内存的时候,他会去映射物理内存,如果发现没有映射关系的话,他会产生一个中断,进入内核态,判断是否有闲置的物理内存,如果有则建立映射关系,如果没有则去进程内存回收(一次swap的换出),看回收完之后的可用内存是否满足你要申请的内存,如果满足则建立映射关系,不满足则触发OOM内存溢出
38.什么是上下文切换?
上下文切换(Context Switch)是指在多任务操作系统中,当CPU从执行一个进程或线程,切换到另一个进程或线程时,保存当前线程或进程的状态,并加载下一个线程或进程的执行状态的过程。这个状态通常被称为“上下文”。
39.协程了解吗?
协程又称微线程,也可以理解它位用户级轻量级线程,最核心的概念就是暂停和恢复(就是函数或者程序能被挂起,然后待会再恢复)
协程和线程相比优点是什么?
协程的上下文切换由用户支配,减少开销
不用担心资源共享问题,不用加锁
在使用多线程的时候,需要考虑同步问题,进行加锁操作,但是协程自身就带同步属性,同一时刻,只有一个协程运行
单线程即可实现高并发,单核 CPU 即便支持上万的协程都不是问题,所以很适合用于高并发处理,尤其是在应用在网络爬虫中
协程的缺点是什么?
它是但线程的,无法实现CPU多核
协程中写的是非阻塞代码,需要使用异步库
协程怎么使用?
Python通过yield提供了对协程的基本支持,但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。
gevent是第三方库,通过greenlet实现协程,其基本思想是:
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成:
from gevent import monkey; monkey.patch_socket()
import geventdef f(n):for i in range(n):print gevent.getcurrent(), ig1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
40.协程的底层是怎么实现的?怎么使用协程?
41.进程的状态以及转化图
三态模型
五台模型
七态模型
42.Linux的内存分区
内核
栈段
局部变量、函数栈等
在Linux中一般为8M,windows中式1M
向下增长
文件映射段
malloc函数调用mmap函数私有匿名映射申请的空间
或者mmap函数共享内存映射,实现进程间通信
堆段
malloc调用brk函数申请的空间
向上增长
BSS段
存储未初始化的静态变量和全局变量
DATA段
存储以初始化的静态变量和全局变量
代码段
存放二进制可执行代码
43.malloc申请内存的时候,操作系统是怎么做的?/内存分配的原理说一下?/进程是怎么分配内存的?
当用户调用malloc的时候,由于malloc是库函数,它需要再调用brk和mmap系统调用函数才能去申请内存空间。当申请空间的大小size < 一个阈值的时候(128K),则会调用brk函数,会申请size这么大小的空间在堆区,并维护一个内存池。当申请的空间大小size > 128K,则会调用mmap函数,它会进行一个私有匿名映射,在文件映射区域申请一段空间,不会创建内存池。
申请的空间总有释放的那一天,当调用free函数的时候,如果是调用brk函数在堆区申请的空间,则不会立即返还给操作系统,而是存放在内存池中,这样做的好处是,当下一次再有申请内存的时候会优先看内存池中是否有合适的空间,如果有合适的,则直接返回给用户,不用进行系统调用了,即不用进行用户态、内核态的互相切换。如果是调用mmap函数在文件映射段申请的空间,则会立即返还给操作系统。
44.为什么不全部使用brk来分配内存?
使用brk来分配内存好处是当内存池中有合适内存的时候,可以直接分配给用户,不用进行俩个状态的切换,速度更快,提高cpu使用效率
缺点也同样明显,内存池中会形成许多内存碎片,如果不经常使用,就会造成内存泄漏的问题。
因此频繁的使用malloc和free去申请和释放小块的内存,会使堆内产生越来越多的内碎片,导致内存泄漏。而这种内存泄漏的现象是valgrind无法检测出来的
valgrind是一款运行在linux下的,用来定位c/c++程序中内存使用方面的错误的工具,包括:内存泄漏、使用未初始化的内存、读/写已释放的内存、读/写内存越界、使用malloc/new/new[]和free/delete/delete[]不匹配,等等。
Valgrind是帮助程序员寻找程序里的bug和改进程序性能的工具。程序通过valgrind运行时,valgrind收集各种有用的信息,通过这些信息可以找到程序中潜在的bug和性能瓶颈。
45.为什么不全使用mmap来分配内存?
mmap申请的空间在free之后会立即返还给操作系统,也就是说每次申请空间都需要内核态和用户态的相互切换,会消耗很多时间。即使用mmap会频繁的进行系统调用。
另外,free之后的mmap虚拟内存处于缺页状态,然后第一次访问的时候会造成缺页中断。
总结:使用mmap会造成频繁的系统调用,和缺页中断问题
所有malloc的实现中充分考虑了brk和mmap的优缺点,默认小于一个阈值使用brk,大于一个阈值使用mmap
46.free函数只传入一个地址,为什么能知道释放多大的内存?
内存池中有记录
47.什么是字节序?怎么判断大小端?有什么用?
字节序就是数据在内存中的存储方式,有大端存储和小段存储
网络字节序是大端存储,主机字节序是小段存储。
48.文件IO
缓冲IO和非缓冲IO的区别有哪些?【是否利用标准库缓存】
缓冲IO
缓冲IO指的是利用标准库的缓存(缓冲区)从而实现加速文件的访问,然后标准库在去调用系统调用访问文件
非缓冲IO
非缓冲IO指的是直接通过系统调用函数访问文件
实例
最常见的printf就是一个缓冲IO,在C中printf使出的内容会被放到缓冲区中,只有遇到换行符才会刷新缓冲区,把缓冲区的内容放到标准输出中让用户看到。这种缓冲机制可以减少系统调用的次数,因为进行系统调用需要用户态和内核态的相互切换,开销很大
与他对立的就是write非阻塞IO,它没有缓冲区,直接输出到终端标准输出
直接IO与非直接IO区别有哪些?【是否利用内核缓冲区缓存】
直接IO
直接IO不会利用OS的内核缓冲区做数据缓存,而是直接访问磁盘
非直接IO
非直接IO会利用OS的内核缓冲区做数据缓存。读操作的时候,内核缓冲区会把数据拷贝给应用程序,写操作的应用程序会把数据拷贝到内核缓冲区中,再由OS去决定什么时候把数据写入磁盘
read和write函数默认都是非直接IO,需要利用内核缓冲区做一个缓存
阻塞IO和非阻塞IO的区别有哪些?
无论是阻塞IO还是非阻塞IO都会经历俩个过程,拿最常用的read函数举例
第一个过程是内核缓冲区中是否有数据
第二个过程是把内核缓冲区中的数据拷贝给应用程序
阻塞IO
当应用程序调用阻塞read函数的时候,会由用户态切换到内核态,然后判断内核缓冲区中是否由想要的数据
如果有数据拷贝数据给应用程序,然后成功返回
如果没有数据则一直阻塞等待,知道缓冲区中有数据为止
非阻塞IO
死轮询内核
当应用程序调用非阻塞read函数的时候,会由用户态切换到内核态,然后判断内核缓冲区中是否有数据,但无论是否有数据都会立即返回,但返回的状态不同,没有数据返回的是一个错误。操作系统不会帮你去实现不间断的轮询内核操作,需要你手动去实现,很简单,就是你获取read的返回值,然后写一个while循环只要返回值是-1则一直循环。这样就实现了一个手动的非阻塞的轮询内核的机制。
手动实现的非阻塞轮询内核这种方式,太消耗资源了,该进程会一直持有CPU,其他什么事都干不了。
多路IO复用机制
它可以在线程的情况下实现多个阻塞IO事件,具体的函数有select、poll、epoll
但是无论是阻塞IO还是非阻塞IO都是同步IO,因为他们在拷贝数据的时候都会需要等待
同步IO和异步IO的区别有哪些?
上面说到无论是阻塞IO还是非阻塞IO都是同步IO,因为即使你第一个判断缓冲区数据是否存在的时候是非阻塞的,但是你第二个过程拷贝数据肯定是需要等待的,所有都是同步IO
真正的异步IO,判断数据准备好之后就会立即返回,数据拷贝的过程由内核自动实现。这个拷贝的过程是异步的
49.聊聊你对多路IO复用的了解?
多路IO复用通常用于socket编程当中,传统的socket编程只能实现1对1的网络通信,为了服务器可以连接更多的客户端,多路IO复用就是其中一种。
多线程模型也可以实现多对1的通信,但是没多一个客户端就要多一个线程,当数量增加到一定程度的时候,这种传统的多线程socket就会产生过度占用内存的瓶颈。
为了解决多线程socket占用内存过度的问题,就出现了多路IO复用。
多路IO复用可以实现一个进程中处理多个阻塞IO。Linux提供了三个API接口,select、poll、epoll。
select和poll没有什么本质区别,都是在内核中维护一个监听位图(128B),该位图用于监听IO事件,当IO事件发生的时候,内核会创建一个触发位图发送给应用程序,应用程序通过遍历整个位图来判断哪些IO事件触发了
epoll则是在内核中维护了一个红黑树和双向链表,红黑树用户监听IO,双向链表用于记录触发了的IO事件,当内核将该双向链表传给应用程序,应用程序只需要遍历链表就可以判断哪些事件触发了。
select的优缺点
缺点
最多只能监听1024个文件描述符
因为位图的大小是128B,1024位,为一个位置监听一个fd,总共可以监听1024个文件描述符
内核空间,用户空间产生了大量的数据拷贝
用户到内核拷贝128,内核到用户128,但是它是一直轮询的,会大量的拷贝
轮询监听,在活跃用户量比较少的时候,性能比较低
举例,比如我初始化位图的时候监听了3~1000的文件描述符,但是实际上只有4 5 6 三个事件被触发了,但是我需要从到到尾遍历一遍,所以在活跃用户量比较少的时候,性能较低
优点
跨平台
window能用 Linux也能用
epoll的优缺点
优点
它监听事件的上限只取决于那块内核空间的大小,不想select一样只能监听1024个文件描述符
没有冗余的数据拷贝,select会有大量冗余的数据拷贝
因为epoll是基于事件通知机制的监听,当事件发生的时候,会把该事件从红黑树拷贝一份放到双向链表中,没有多余的拷贝
epoll基于事件通知机制的监听,及时活跃用户很少,也可以保证效率
因为它遍历的是已给双向链表,不像select一样遍历真个数组
缺点
不跨平台
用户少的时候不太合适,因为内核中维护的数据结构过大
红黑树、双向链表
50.如何查看哪些进程持有CPU?
使用top或者htop指令
51.创建硬链接和软连接的指令是什么?
硬链接
ln ./a.txt ./b.txt // 给a.txt创建了一个硬链接b.txt,他俩指向同一个inode
软连接
ln -s ./a.txt ./b.txt // 给a.txt创建了一个软连接b.txt,b.txt里面存放的是a.txt的路径
52.查看文件内容常见的指令
cat/tac
less
可以pageup/pagedown进行翻页
tail
用于查看日志文件
vim
一会用于编辑,但是也可以查看
53.Linux中如果使用GDB调式?
Linux | 调试器GDB的详细教程【纯命令行调试】_linux gdb 调试教程-CSDN博客
一个可执行文件分为俩个版本,一个是debug版本(程序源用于调式的版本),另外一个是relase版本(测试人员用于测试的,测试通过上线给用户)
只有debug模式的才能用gdb工具调试,因为它里面有调试信息,而relase模式的不能用gdb调试。换句话来说debug模式的可执行文件要比relase模式的大,多的就是调试信息
使用gdb调试的命令
l (显示文件内容带行号)
l 0 -->从第一行开始显示10行
l 1 -->从第一行开始显示10行
l -->随机显示10行
回车 -->继续显示下面的10行
l 函数 -->显示这个函数
b(短点设置)
b 10 -->在第10行打一个断点
b func -->在func函数的第一行打一个断点
info b(显示所有断点信息)
d(删除断点)
d 1 -->删除1编号的断点
d breakpoints -->删除所有的断点
disable(设置断点不可用)
disable b --> 把所有断点设置位不可用
disable b 2 -->把二号编号的断点设置位不可用
enable(设置断点可用)
disable b --> 把所有断点设置位可用
disable b 2 -->把二号编号的断点设置位可用
run(执行程序)
n(next逐过程执行)
不会进入函数里面
s (step逐语句执行)
会进入函数里面,库函数也会进入
p(打印变量值)
p i -->打印i的变量值
但是每次暂停都要手动调用p i才能出结果
display(追踪打印)
display i
每次暂停不需要手动调用就能出变量结果
undisplay(取消追踪打印)
bt(查看函数调用)
set var(修改变量的值)
set var i = 8
until(跳转指定的行数)
until 13 -->跳转到13行
finish(强制执行当前函数,执行到当前函数返回值为止停下来)
c(continue挑战到下一个断点)
54.Coredump/core/cure
定义
当程序异常终止或者崩溃的时候,OS内核会将内存状态记录下来,存储到core文件中,这种行为叫做核心转存(core dump)
利用core dump 可以快速确定程序崩溃的为止,通常情况下core文件中会包含程序运行时候的内存、寄存器状态、堆栈指针状态、内存管理信息等等。
core dump核心转存产生的集中可能情况
内存越界
数组下标越界
字符串没有\0结束标志
strcpy或者mempcy的时候长度传多了
多线程程序使用了不安全的函数
多线程访问全局变量的时候需要加锁保护,否则很容易造成coredump
非法指针
空指针等
使用gdb调试core文件
常见的操作
l
b
d
info b
r
display
undisplay
n
s
until
finish
c
55.tcpdump命令
tcpdump 是一个运行在命令行下的抓包工具。它允许用户拦截和显示发送或收到过网络连接到该计算机的TCP/IP和其他数据包。
用简单的话来定义tcpdump,就是: dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具。tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。
实用命令实例
-
将某端口收发的数据包保存到文件
-
sudo tcpdump -i any port端口-w文件名.cap
-
打印请求到屏幕
-
sudo tcpdump -i any port端口-Xnlps0
-
默认启动
-
tcpdump
-
普通情况下,直接启动tcpdump将监视第一个网络接口上所有流过的数据包。
-
监视指定网络接口的数据包
-
tcpdump -i eth1
-
如果不指定网卡,默认tcpdump只会监视第一个网络接口,一般是eth0,下面的例子都没有指定网络接口。
tcpdump采用命令行方式,它的命令格式为:
tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ]
[ -i 网络接口 ] [ -r 文件名] [ -s snaplen ]
[ -T 类型 ] [ -w 文件名 ] [表达式 ]
tcpdump的选项介绍
-a 将网络地址和广播地址转变成名字;
-d 将匹配信息包的代码以人们能够理解的汇编格式给出;
-dd 将匹配信息包的代码以c语言程序段的格式给出;
-ddd 将匹配信息包的代码以十进制的形式给出;
-e 在输出行打印出数据链路层的头部信息,包括源mac和目的mac,以及网络层的协议;
-f 将外部的Internet地址以数字的形式打印出来;
-l 使标准输出变为缓冲行形式;
-n 指定将每个监听到数据包中的域名转换成IP地址后显示,不把网络地址转换成名字;
-nn: 指定将每个监听到的数据包中的域名转换成IP、端口从应用名称转换成端口号后显示
-t 在输出的每一行不打印时间戳;
-v 输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息;
-vv 输出详细的报文信息;
-c 在收到指定的包的数目后,tcpdump就会停止;
-F 从指定的文件中读取表达式,忽略其它的表达式;
-i 指定监听的网络接口;
-p: 将网卡设置为非混杂模式,不能与host或broadcast一起使用
-r 从指定的文件中读取包(这些包一般通过-w选项产生);
-w 直接将包写入文件中,并不分析和打印出来;
-s snaplen snaplen表示从一个包中截取的字节数。0表示包不截断,抓完整的数据包。默认的话 tcpdump 只显示部分数据包,默认68字节
-T 将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程调用)和snmp(简单网络管理协议;)
-X 告诉tcpdump命令,需要把协议头和包内容都原原本本的显示出来(tcpdump会以16进制和ASCII的形式显示),这在进行协议分析时是绝对的利器。
(*)56.crontab命令
57.查看后台进程
top
查看所有进程类似于window下的资源管理器
ps
查看后台进程
jobs
查看当前控制台的后台进程
58.操作系统的主要功能是什么?
管理硬件资源
提供可视化图形界面
为其他软件提供服务
59.为什么Linux下的应用程序不能直接在Windows下运行?
Linux系统和Windows系统的格式不同
API系统调用接口也不同
60.为什么称为陷入内核?
计算机软件结构的分层图如下,最外层是应用程序(用户态),里面是操作系统内核(内核态)
当应用程序想要访问系统资源的时候,就会发起系统调用,由用户态切换到内核态,这个过程被称为陷入内核。
61.什么是用户态和内核态?
在一个32位的OS中,虚拟内存的大小位4GB,其中,1G的内核空间+3G用户空间。
用户态
CPU可以执行部分指令,并且无法直接访问硬件资源,需要进行系统调用到用户态才能访问硬件资源。这种模式下的操作权限比较低,主要用于应用程序使用
内核态
CPU可以执行全部指令,并且可以直接访问所有的硬件资源,具有更高的操作权限,主要用于操作系统内核使用
内核态和用户态的划分可以保证OS的安全性、稳定性和隔离性。
安全性:防止恶意的应用程序对系统资源进行破坏
稳定性:用户态出现问题,不应影响到OS内核
隔离性:内核态和用户态的划分使得操作系统内核与应用程序之间有了明确的边界,有利于系统的模块化和维护
62.内核态和用户态如何切换?
内核态与用户态转换的三种方式
系统调用
产生的是软件中断
异常
例如常见的内存映射的时候出现的缺页中断
外围设备的中断
当一个阻塞事件完成的时候,会发出一个中断信号,这是CPU会暂停实行下一个指令,转为去执行中断序号的处理程序,处理程序最开始应处于用户态,然后回完成用户态到内核态的切换。
三种切换发生都是因为执行了中断,实际上系统调用就是中断机制实现的
63.什么是内核?
内核时操作系统的核心,是帮助操作系统用来管理硬件资源的。
boot loader了解一下?
boot loader 又被称为引导加载程序,能够将计算机OS放入内存中,在电源通电或者计算机重启时,BIOS会执行一些初始化测试,然后将控制权转移到引导加载程序所在的主引导记录(MBR)
BIOS的功能
总结: 就是一个加载在计算机主板上最基础的一段程序,负责最基础的硬件控制和设置。
64.什么是实时系统?
实时操作系统就是对时间做了严格要求的操作系统
实时操作系统分为两类
硬实时操作系统
规定在某个时刻内某个动作必须发生或完成,否则会产生永久性的损伤
例如导弹发射系统,规定16:39分49秒发射,差一秒对面的导弹就打过来了
例如汽车生产车间,焊接机器必须在某以时刻焊接完成,早了晚了都会对汽车造成永久性损伤
软实时操作系统
在某一个时刻某个动作没有发生是可以接收的,不会造成永久性随上,但是只能是个别事件。
例如手机就属于软实时操作系统
主要判断依据就是某一时刻,某件事情不发生是否会对OS产生永久性损伤
(*)65.Linux操作系统的启动过程
Linux操作系统的启动过程_linux操作系统的一般启动过程-CSDN博客
Linux系统启动流程(超详细)-CSDN博客
Linux操作系统的启动过程一般分为四个阶段:
- BIOS启动引导阶段;
- GRUB启动引导阶段;
- 内核阶段;
- init初始化阶段。
66.多处理器系统的优势
多处理器操作系统的特点:
- 并行处理:支持同时运行多个进程或线程,能够更高效地利用CPU资源。
- 负载均衡:能够根据各个处理器的负载情况,将任务合理分配到不同的处理器上,提高系统性能。
- 共享资源:多个处理器可以共享内存、I/O设备等资源,方便数据的访问和处理。
- 提高系统稳定性:一旦某个处理器出现故障,其他处理器仍然可以继续运行,增加系统的可靠性。
67.什么是进程和进程表?
进程就是运行起来的程序,是操作系统进行资源分配的基本单位。
操作系统为了跟踪每个进程的活动状态,维护了一个进程表。在进程表的内部,可以看到进程的状态和每个进程使用资源的情况
68.使用多线程的好处是什么?
提高程序的运行效率
多线程和多进程都可以实现程序的并发执行,并发执行可以提高程序的运行效率。
提高资源利用率
但是多线程创建的代价小,因为多个线程共享同一个进程的资源,提高资源利用率。
通信简单
多线程之间的通信是比较容易的,但是多进程之间的通信困难。
增强程序的相应性
在实现简单的socket服务器的时候,可以用多线程解决多个阻塞IO的问题,增强程序的响应性。
69.进程终止的方式
正常退出
主函数return 0
错误退出
exit(-1)
严重错误
程序发生段错误了
被其他进程杀死
其他进程调用kill函数了
70.影响调度程序的指标是什么?
服务时间
CPU使用率
吞吐量
周转时间
71.为什么要内存分段?
不分段没有虚拟内存的话,一个程序运行俩次,两个进程之间会互相影响,因为他们访问的时同一块物理地址。
但是进行内存分段的话,会有一个通过段表的地址映射,俩个进程访问的时不同的物理地址
模块化管理
72.物理地址、逻辑地址、有效地址、线性地址、虚拟地址的区别?
在段表中,物理地址 = 段的基地址 + 段内偏移量
这个段内偏移量被称为有效地址和逻辑地址
在实模式下,段的基地址 + 段内偏移量得到的就时物理地址
但时在保护模式下,段的基地址 + 段内偏移量得到的是线性地址,如果还有分页的话这个地址被叫做虚拟地址
73.OS空间内存的管理方式
空闲链表
空闲里面里面不仅记录空闲的内存结点而且还有已经被占用的内存结点
位图
(*)74.页面置换算法都有哪些?
(*)75.提高文件系统性能的方式
高速缓存
减少磁盘的IO次数
块提前读
减少磁盘臂的运动
磁盘碎片管理
(*)76.磁盘臂调度算法
(*)77.RAID的不同级别(磁盘阵列)
RAID称为磁盘冗余阵列,简称磁盘阵列。利用虚拟化技术把多个硬盘结合在一起,成为—个或多个磁盘阵列组,目的是提升性能或数据冗余。
RAID有不同的级别
- RAID 0-无容错的条带化磁盘阵列
- RAID 1-镜像和双工
- RAID 2-内存式纠错码
- RAID 3-比特交错奇偶校验·
- RAID 4-块交错奇偶校验
- RAID 5-块交错分布式奇偶校验
- RAID 6-P +Q冗余
(*)78.中断处理的过程
中断处理方案有很多种,下面是《ARM System Developer’s GuideDesigning and Optimizing system Software》列出来的一些方案
- 非嵌套的中断处理程序按照顺序处理各个中断,非嵌套的中断处理程序也是最简单的中断处理
- 嵌套的中断处理程序会处理多个中断而无需分配优先级
- 可重入的中断处理程序可使用优先级处理多个中断
- 简单优先级中断处理程序可处理简单的中断
- 标准优先级中断处理程序比低优先级的中断处理程序在更短的时间能够处理优先级更高的中断
- 高优先级中断处理程序在短时间能够处理优先级更高的任务,并直接进入特定的服务例程。
- 优先级分组中断处理程序能够处理不同优先级的中断任务
下面是一些通用的中断处理程序的步骤,不同的操作系统实现细节不一样
- 保存所有没有被中断硬件保存的寄存器
- 为中断服务程序设置上下文环境,可能包括设置TLB、MMu和页表
- 为中断服务程序设置栈
- 对中断控制器作出响应,如果不存在集中的中断控制器,则继续响应中断
- 把寄存器从保存它的地方拷贝到进程表中
- 运行中断服务程序,它会从发出中断的设备控制器的寄存器中提取信息
- 操作系统会选择一个合适的进程来运行。如果中断造成了一些优先级更高的进程变为就绪态,则选择运行这些优先级高的进程
- 为进程设置MMU 上下文,可能也会需要TLB,根据实际情况决定加载进程的寄存器,包括PSW寄存器
- 开始运行新的进程
(*)79.什么是设备驱动程序?
设备控制器是一个可编址的设备,当它仅控制一个设备时,它只有一个唯一的设备地址;如果设备控制器控制多个可连接设备时,则应含有多个设备地址,并使每一个设备地址对应一个设备。
设备控制器主要分为两种:字符设备和块设备
设备控制器的主要功能有下面这些
- 接收和识别命令:设备控制器可以接受来自CPU的指令,并进行识别。设备控制器内部也会有寄存器,用来存放指令和参数
- 进行数据交换:CPU、控制器和设备之间会进行数据的交换,CPU通过总线把指令发送给控制器,或从控制器中并行地读出数据;控制器将数据写入指定设备。
- 地址识别:每个硬件设备都有自己的地址,设备控制器能够识别这些不同的地址,来达到控制硬件的目的,此外,为使CPU能向寄存器中写入或者读取数据,这些寄存器都应具有唯一的地址。
- 差错检测:设备控制器还具有对设备传递过来的数据进行检测的功能。
(*)80.什么是DMA?
不需要CPU参与去访问内存的方式
DMA的中文名称是直接内存访问,它意味着CPU授予VO模块权限在不涉及CPU的情况下读取或写入内存。也就是DMA可以不需要CPU的参与。这个过程由称为DMA控制器(DMAC)的芯片管理。由于DMA设备可以直接在内存之间传输数据,而不是使用CPU作为中介,因此可以缓解总线上的拥塞。DMA通过允许CPU执行任务,同时DMA 系统通过系统和内存总线传输数据来提高系统并发性。
81.DMA访问内存的特点
DMA方式有如下特点:
-
数据传送以数据块为基本单位
-
所传送的数据从设备直接送入主存,或者从主存直接输出到设备上
-
仅在传送一个或多个数据块的开始和结束时才需CPU的干预,而整块数据的传送则是在控制器的控制下完成。
DMA方式和中断驱动控制方式相比,减少了CPU对I/O操作的干预,进一步提高了CPU与I/O设备的并行操作程度。
DMA方式的线路简单、价格低廉,适合高速设备与主存之间的成批数据传送,小型、微型机中的快速设备均采用这种方式,但其功能较差,不能满足复杂的I/O要求。
82.如何破坏死锁?
死锁产生的必要条件有四个:互斥条件、持有并等待条件、环路等待条件、不可剥夺条件
1.不加锁(不太现实奥)
2.锁的力度控制:尽量减少持有锁的时间,降低死锁发生概率
3.资源有序分配:破坏环路条件1 2 1 2
4.重试机制:破坏不可剥夺条件,一般为非阻塞的trylock
83.计算密集型任务和IO密集型任务
计算密集型任务
-
特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。
-
虽然可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPu的核心数。
IO密集型任务
-
涉及到网络、磁盘IO的任务都是lO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待lo操作完成(因为IO的速度远远低于CPU和内存的速度)。
-
对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。