命令或 Bash 相关
Bash 中两个数做运算的几种方式
1 | sum=$[ ${v1} + ${v2} ] |
$?,$*
等相关参数都有什么意义
1 | $$: shell 本身的 processID |
read
命令从管道中读取字节流
1 | echo "sinaops" | read a ; echo $a # 输出为空 |
find
使用
1 | # 把 /data 目录及其子目录下所有以扩展名 .txt 结尾的文件中包含 magedu 的字符串全部替换为 magestudy |
grep,sed,awk
的运用
1 | # 统计域名出现次数 "http://hi.baidu.com/browse/" |
为 history
添加时间戳,如何防止个人 history 操作泄露
设置 export HISTTIMEFORMAT='%F %T'
环境变量后,以后记录的命令历史操作就会添加时间
- 可以将
history
记录的个人操作清空,使用history -c
清空当前命令历史,并使用history -w
将已经清空的命令历史写入到命令历史文件~/.bash_history
中(或直接清空该文件),下次登录边不再有命令历史 - 可以设置
export HISTCONTROL=ignorespace
环境变量,使得命令历史忽略记录以空格开始的命令.在执行敏感命令时,以空格开始 - 可以设置
export HISTIGNORE=*
环境变量,使命令历史忽略记录所有命令.使用export HISTIGNORE=
恢复记录.
系统相关
进程和线程有什么区别
- 进程(process)是系统进行资源分配和调度的基本单位,线程(Thread)是 CPU 调度和分派的基本单位
- 线程依赖于进程而存在,一个进程至少有一个线程
- 进程有自己的独立地址空间,线程共享所属进程的地址空间
- 进程是拥有系统资源的一个独立单位,而线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),和其他线程共享本进程的相关资源如内存,I/O,cpu 等
- 在进程切换时,涉及到整个当前进程 CPU 环境的保存环境的设置以及新被调度运行的CPU环境的设置,而线程切换只需保存和设置少量的寄存器的内容,并不涉及存储器管理方面的操作.进程切换的开销远大于线程切换的开销
- 线程之间的通信更方便,同一进程下的线程共享全局变量等数据,而进程之间的通信需要以进程间通信(IPC)的方式进行
- 多线程程序只要有一个线程崩溃,整个程序就崩溃了.但多进程程序中一个进程崩溃并不会对其它进程造成影响,因为进程有自己的独立地址空间
进程间通信方式
- 管道
- 消息队列
- 信号和信号量
- 共享内存
- 套接字
并发,并行,异步的区别
- 并发: 在一段时间内交替做不同事情的能力,可以理解为单线程(协程)/多线程运行在单核处理器上,如果有其中一个任务/线程阻塞,CPU 立即切换,执行行另一个任务/线程的代码逻辑
- 并行: 在同一时刻做不同事情的能力,可以理解为多线程程序运行在多核处理器上,一个线程绑定一个 CPU,多个 CPU 同时处理代码逻辑
什么是 IO 多路复用?怎么实现
IO 多路复用是指单个进程/线程就可以同时处理多个IO请求.是一种可以监视多个描述符,一旦某个描述符就绪,能够通知程序进行相应的读写操作的机制.
select/poll/epoll三者的区别?
select
将文件描述符放入一个集合(缺点1: 集合大小有限制,32 位机器默认是1024,64 位默认是 2048
)中,调用 select 时,将这个集合从用户空间拷贝到内核空间(缺点2: 每次都要将集合从用户空间复制到内核空间,开销大
),由内核根据就绪状态修改该集合的内容.采用水平触发机制.select 函数返回后,需要通过遍历这个集合(缺点3: 轮询的方式效率较低
),找到就绪的文件描述符.当文件描述符的数量增加时,效率率会线性下降
poll
和 select 几乎没有区别,区别在于文件描述符的存储方式不同.poll 采用链表的方式存储,没有最大存储数量的限制
epoll
- 通过内核和用户空间共享内存,避免了不断复制的问题.
- 支持的同时连接数上限很高
- 文件描述符就绪时,采用回调机制,避免了轮询
- 支持水平触发和边缘触发.采用边缘触发机制时,只有活跃的描述符才会触发回调函数
什么是用户态和内核态
为了限制不同程序的访问能力,防止一些程序访问其它程序的内存数据,CPU 划分了用户态和内核态两个权限等级
- 用户态只能受限地访问内存,且不允许访问外围设备.没有占用 CPU 的能力,CPU 资源可以被其它程序获取
- 内核态可以访问内存所有数据以及外围设备,也可以进行程序的切换
所有用户程序都运行在用户态,但有时需要进行一些内核态的操作,比如从硬盘或者键盘读数据,这时就需要进行系统调用,使 CPU 切换到内核态,执行相应的服务,再切换为用户态并返回系统调用的结果.
为什么要分用户态和内核态
- 安全性: 防止用户程序恶意或者不小心破坏系统/内存/硬件资源;
- 封装性: 用户程序不需要实现更加底层的代码
- 利于调度: 如果多个用户程序都在等待键盘输入,这时就需要进行调度.统一交给操作系统调度更加方便
如何从用户态切换到内核态?
- 系统调用: 比如读取命令行输入.本质上还是通过中断实现
- 用户程序发生异常时:比如缺页异常
- 外围设备的中断: 外围设备完成用户请求的操作之后,会向 CPU 发出中断信号,这时 CPU 会转去处理对应的中断处理程序
死锁
什么是死锁
在两个或者多个并发进程中,每个进程持有某种资源而又等待其它进程释放它们现在保持着的资源,在未改变这种状态之前,两个进程都不能向前执行,称这一组进程产生了死锁(deadlock).如
1 | 线程 A -> 锁定 a -> 尝试锁定 b -> 永久等待 |
死锁产生的必要条件
- 互斥: 一个资源一次只能被一个进程使用
- 占有并等待: 一个进程至少占有一个资源,并在等待另一个被其它进程占用的资源
- 非抢占: 已经分配给一个进程的资源不能被强制性抢占,只能由进程完成任务之后自愿释放
- 循环等待: 若干进程之间形成一种头尾相接的环形等待资源关系,该环路中的每个进程都在等待下一个进程所占有的资源
进程的有效用户与实际用户
- Linux系统中某个可执行文件属于 root 并且有 setid,当一个普通用户 mike运行这个程序时,产生的进程的有效用户和实际用户分别是 root 和 mike
fork()
创建进程
下面程序共有多少进程
1 | /* |
ln -s
与 mv
对某文件操作时,对 inode 和 block 有什么影响
1 | # 理解 blocks 为磁盘存储块, inode 为指向该存储块的地址 |
free
命令查看内存时,buffer 和 cache 各表示什么含义?如何清理 cache 缓存
这二者是为了提高IO性能的.
- buffer是即将要被写入磁盘的,buffer 能够使分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能;
- cache是被从磁盘中读出来的.cached 是把读取过的数据保存起来,重新读取时若命中就不要去读硬盘,若没有命中就读硬盘
1 | sync |
top 页面含义
1 | 当前时间及运行时长, 登录用户数, 平均负载 |
kill
信号
1 | 1 HUP 终端断线 |
tcpdump
抓包
1 | -i <DEV>: 抓取指定网络接口的数据包 |
日志出现 kernel:nf_conntrack:tablefull,dropping packet
错误
此错误表示连接跟踪表已满,开始丢包,可能的原因是由于频繁的连接/关闭,或者网络的一些 TCP 的连接导致的
解决方法:
- 加大跟踪表的大小
net.netfilter.nf_conntrack_max
- 禁用一些不必跟踪的连接状态
- 禁用
ip_vs
,nf_conntrack
模块
sar 命令
统计,报告,保存系统运行状态信息
1 | sar [m [n]]: 每隔 m 秒报告一次,共报告 n 次,默认是 CPU 状态信息 |
文件描述符
文件描述符是一个非负的索引值,指向内核中的”文件记录表”.
- 当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符
- 当需要读写文件时,文件描述符可作为参数传递给相应的函数
- Linux 下所有对设备和文件的操作都使用文件描述符来进行
常见文件描述符如下
- 0: 表示标准输入,对应宏为:
STDIN_FILENO
,函数 scanf() 使用的是标准输入 - 1: 表示标准输出,对应宏为:
STDOUT_FILENO
,函数 printf() 使用的是标准输出 - 2: 表示标准出错处理,对应的宏为:
STDERR_NO