kernal和cpu
kernel: 负责系统管理,比如内存管理,屏蔽了对硬件的操作。
cpu: 硬件层面上的,处理各种指令,提供运算
系统调用
程序都是运行在用户态的。
用来使用系统态级别的子功能的入口。
文件存储
inode
inode:index node, 维护文件的属性信息
文件数据存储在块里。另外还需要inode来存储文件的元信息:某个文件被分成了几块,每一块的地址,文件拥有者,创建时间,权限,大小等。
每个 inode都有一个号码,linux使用inode号码区分不同的文件
使用stat a.txt
查看inode信息
目录
- /bin: 所有二进制可执行文件,常用命令
- /etc 系统管理和配置文件
- /home 存放所有用户文件的根目录,用户主目录的基点。
- /usr 系统应用程序
- /opt tomcat等安装在这里。额外安装的可选应用程序包一般在这里
- root 系统管理员住目录
- /sbin 二进制可执行文件,系统管理员使用的系统级别的管理命令和程序。ifconfig等
- /dev 用来存放设备文件
- /mnt 让用户临时挂载其他的文件系统
- /boot 系统引导时的各种文件
linux基本命令
-
增删改查
cp -r 目录名,目录拷贝的目标位置
-r代表递归: 如果给出的源文件是目录文件,则将复制目录下所有的子目录和文件。ls ll区别: ll == ls -l , ll是查看目录下所有目录和文件的详细信息。(例如权限等)
more一页一页查看
cat查看全部文件, cat filename.txt | more
-
打包并压缩
tar -zcvf [压缩后的文件名] [要打包压缩的文件]
z: 调用gzip压缩命令进行压缩
c: 打包文件
v: 显示运行过程
f: 显示文件名解压: tar [-xvf] 压缩文件
tar -xvf test.tar.gz
x: 解压 -
开发和调试程序
netstat 显示网络相关的信息,如网络连接,路由表(-r),接口状态
-a (all) 显示全部信息tcpdump 对网络上的数据包进行截获的包分析工具。
ipcs提供进程间通信方式的信息,包括共享内存,信号量,消息队列。
-a 输出所有
-m 共享内存
-q 消息队列
-s 信号ipcrm 移除一个消息对象、或者共享内存、或者信号量
-
文本处理
grep 文档详细查找
linux中的权限:
r: 可读。可以使用cat查看文件的内容
w: 可写。可以修改文件的内容
x: 可执行。可将其运行为二进制文件。
- 查看所有者:
ls -ahl
, 修改所有者:chown 用户名 - 查看文件所在组:
ls -ahl
, 修改所有者:chgrp 组名 - 其他组:除了这个文件的所有者和所在组的用户外,其他所有用户都属于这个
- 修改权限
chmod
linux用户管理
多用户多任务的分时操作系统。
为什么用户之间可以共享文件
shell
Shell是用户与Linux系统之间的接口.用户登录后,要启动一个进程,负责将用户的操作传给内核. 这个进程是用户登陆到系统以后运行的命令解释器。就是shell.
利用这一特点,我们可以限制用户只能运行指定的应用程序
其他命令
常用命令:
grep 要搜索的字符串 要搜索的文件 --color(color表示高亮)
grep 更适合单纯的查找或匹配文本,sed 更适合编辑匹配到的文本,awk 更适合格式化文本,对文本进行较复杂格式处理
ps -ef/ ps -aux 查看当前系统正在运行进程。展示格式不同. ps aux|grep redis查看包括redis字符串的进程
如何排查进程之间的父子关系(pid ppid),怎么判断进程是僵尸进程,ps 能看到啥信息
top
能看到什么系统信息
kill
awk
netstat(什么场景使用到它)
linux中进程的几个状态:
-
Z 僵尸
kill命令对僵尸进程无效。子进程死了之后,会对父进程发送一个信号。父进程一般利用是忽视。父进程也可以用wait来响应,这时wait可以回收这个僵尸子进程。僵尸进程如果不回收,将保留页表项,导致资源泄露。 -
S 休眠
-
D 不可中断的休眠
-
R 运行
-
T 停止时跟踪
-
kill -9 进程的pid : 杀死进程(-9表示强制终止)
disown -r 将所有正在运行的进程移除 -
查看后台任务:job -l
-
把后台任务调到前台:fg
-
把停下来的后台任务在后台执行bg, 调整到前台执行:fg
-
kill [-s <信息编号>] [程序] 或者 [-l <信息编号>]
kill -9 pid -
查看系统支持的所有信号: kill -l
-
dirs 查看当前目录栈
-
wc 文件多少行多少个字
-
hash 执行过的命令的完整路径,打印所用过的命令以及执行的次数
-
let 可以进行整数型的数学运算
-
网络通信命令
查看当前系统的网卡信息:ifconfig
查看与某台机器的连接情况:ping
查看当前系统的端口使用: netstat -an
shutdown -h now: 现在关机
reboot -w: 重开机
常见的内存管理机制
- 块式管理:将内存固定的分成几个块,每个块只包含一个进程。
- 页式管理:将内存分成一页一页的格式,每页大小固定。页比较小。出发点是更好满足内存管理的需求。
- 段式管理:按照程序员设定的逻辑分段。每段大小是不同的。每段内部是连续的,之间是不连续的。
- 段页式:把主存先分成若干段,每段再分页。
虚拟地址到物理地址的转换是个问题。需要解决虚拟地址空间大,所以页表也会很大。
块表是什么: 分页管理中,页表的一部分,存放的是虚拟地址到物理地址的转换。存储在cache里,加速虚拟地址到物理地址的转换。
多级页表:避免所有的页表都放到内存中占地方太大。时间换空间。
共享内存
建立软连接和硬链接(文件共享)
1. 硬连接:
(基于索引结点的文件共享方式)。每个文件有一个索引节点,inode中存在一个链接计数count。加入当用户B想要共享这个文件,那么用户B的目录中会增加一个目录项,并设置一个指针来指向该文件的索引结点。链接计数+1.
当B不想访问时,只能将count数目-1,count数目不是0的时候不能删除该文件。
ln link source
2. 软连接:
(利用符号链的共享方式)。比如让用户B共享A的一个文件F,系统会创建一个link类型的新文件取名为F. 将文件F写到用户B的目录里。这个文件F里,包括里B中F文件的路径。只有文件所有者才有指向索引结点的指针。这样不会留下悬空指针的问题。于是拥有者可以删除文件。这时候其他用户根据符号链再去访问时会发生访问失败,于是将符号链删除。(这个路径包括文件所在机器的网络地址和该机器中的文件路径。涉及多次读盘)
ln -s slink source
内存共享的实现原理
一件是在内存划出一块区域来作为共享区;另一件是把这个区域映射到参与通信的各个进程空间。
- 内存映射:通过系统调用mmap()把这个文件所占用的内存空间映射到参与通信的各个进程地址空间,则这些进程就都可以看到这个共享区域,进而实现进程间的通信。
查看共享内存: ipcs -m
删除共享内存,使用命令:ipcrm -m [shmid]
共享内存什么时候会释放
用户为什么可以访问其他用户的空间
linux的容器:
namespace/cgroup对系统资源做了一层抽象,让系统资源对进程部分可见,在同一个namespace中的进程,可看到系统资源是一样的。
虚拟内存是什么
-
使用硬盘空间扩充内存:访问的信息不在内存时,os将需要的部分调入内存。将不需要的还出。这样系统就为用户维护了一个大得多的存储器,就是虚拟存储器。虚拟存储器的大小由计算机的地址结构决定。
-
定义了一个连续的虚拟地址空间。让每个进程都拥有一片完成的内存空间。
逻辑地址、虚拟地址、物理地址
逻辑地址:由程序产生的与段相关的偏移地址部分。比如指针的值就是逻辑地址 。机器语言指令中用来指定一个操作数或一条指令的地址
物理地址:实际的地址
虚拟地址:由计算机的地址结构决定。系统中的每个进程所使用的地址。比内存空间大很多。具体访问到哪个物理地址要看MMU将线性地址转换后的物理地址才能知道。
虚拟内存的技术实现
内存管理需要是离散的:请求分页,请求分段,请求段页式存储。
页面置换算法:
缺页中断:需要访问的页没在内存。
最佳页面置换算法:以后不怎么用的(无法实现
FIFO页面置换算法
LRU: 最近最久未使用页面置换算法(双链表和hashmap,hashmap的value存放链表指针,每次操作将对应的双链表中的值放到双链表的末尾)
LFU: 最少使用页面置换算法
linux中的锁
-
原子操作
避免操作被进程/线程的调度打断。不会出现上下文切换
实现方式:指令执行期间,给总线加锁(x86)
-
自旋锁spinlock
使用者想用临界区资源时,如果已经加锁,则不会阻塞,而是原地轮训资源判断是否释放锁。不会出现上下文切换。
调用线程不会阻塞,但是轮训访问消耗cpu
实现方式:CAS: compare and switch
- While( CAS(value1, value2, value3 )) // 轮训访问,直到value1 == value2 时候,将value3赋值该value1
使用场景:预计线程持有时间短。则互斥锁两次上下文切换的开销 > 自旋锁消耗的cpu
代码经常需要加锁,但是实际情况产生竞争的情况比较少。 -
互斥锁
获得不了互斥锁就被阻塞(挂起),由系统唤醒。
开销:需要从用户态切换到内核态,申请到锁之后从内核态切换到用户态。这个过程产生两次上下文切换。使用资源后释放锁,从用户态切换到内核态,操作系统唤醒阻塞等待锁的其他进程,进程返回用户态。又有两次
涉及到缓存、tlb的更新,记录当前进程的堆栈和寄存器中的值。
目的:保护临界区
条件变量:线程间共享的同步变量进行同步。用来等待线程而不是上锁。
场景:被保护的资源需要睡眠
-
读写锁
共享锁和互斥锁。
读优先的读写锁:读加锁时,任何线程都可以对其进行读加锁操作。但是所有试图进行写加锁的操作都会被阻塞。
-
可重入锁和不可重入锁
Mutex可以分为递归锁(recursive mutex)和非递归锁
- 可重入(递归):
- 非递归:pthread_mutex_t
二者唯一的区别是,同一个线程可以多次获取同一个递归锁,不会产生死锁。而如果一个线程多次获取同一个非递归锁,则会产生死锁
mmap: 将内核空间的一段内存区域映射到用户空间。映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,相反,内核空间对这段区域的修改也直接反映用户空间。内核空间对这段区域的修改就直接反映给了用户空间。所以可以实现进程间的文件共享
- 1 (创建虚拟空间)进程启动映射过程,并在进程的虚拟空间中创建连续的虚拟映射区域
- 2 (完成地址映射)调用内核空间的系统调用函数mmap,实现文件磁盘地址和进程虚拟地址的映射。
- 3 进程发起对映射空间的访问。缺页。文件内容copy到物理内存中。这个时候因为建立了和文件磁盘地址的映射,所以只需要一次数据拷贝,就能从磁盘将数据写入内存的用户空间。
和正常状态下读写的区别:mmap更高效。因为它类似于一个指针,直接指向了磁盘空间中的文件,对文件的读写利用这个指针,而不需要调用read write等系统调用函数。直接读写,不用去根据逻辑地址查找页表才能的得到物理地址。然后再去修改。节省了一次页表查询时间。
更新文件很多的时候不适合mmap,因为有大量的回写。
进程
数据段、代码段、pcb进程控制快
场景:多进程方式:nginx, 一个master多个worker; 多线程方式:web server。每当有一个请求,就使用一个线程去处理请求。
linux中的folk, exec, exit, wait sleep
- folk: 用户创建进程的唯一方法
一个进程运行folk生成子进程。子进程拥有父进程的代码段和数据段和栈。不同的是pid不同。
写时拷贝:创建子进程时,并不立即复制地址空间,拥有相同的地址空间。当父子进程有一方想要写,则内核申请一个新的物理页,将原物理也中的内容复制到新的物理页中。这个时候父子进程有自己的各自物理内存页。
- exec
根据指定的文件名找到可执行文件,并用它来取代调用进程的内容。让子进程丢弃当前拷贝父进程的代码段,创建新的代码段和堆栈。
- exit
进程结束函数。在结束进程前,检查进程打开了哪些文件,把文件缓冲区中的内容写回文件。
_exit:直接结束进程,清除使用的内存空间,清除内核中各种数据结构。
区别:他们都写入内存,_exit满足条件才写入文件。所以exit可以保证数据完整性。
- wait and sleep
wait释放了锁,等待上一批或者一个脚本执行完(进程执行完),再执行wait之后的命令。
具体措施:父进程调用了wait时,阻塞自己。wait等待当前进程的某个子进程是否已经执行完退出。如果找到了一个退出的变成僵尸的子进程,wait就会销毁这个子进程后返回,执行后面的命令;如果没有就一直阻塞在这里
sleep 制定挂起进程的秒数。时间到了就自动返回。
共享内存存在进程的哪里,共享内存段段最大的限制
共享内存存在进程的数据段,最大限制是0x2000000Byte
堆栈存储
- 堆:存放一些程序员声明的对象,是由malloc之类函数分配的空间所在地。java中用专门的gc回收
- 栈:存放函数的参数值,局部变量(因为属于线程)
- 全局区:全局变量和静态变量,程序结束后,系统自动释放。
- 文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
- 程序代码区—存放函数体的二进制代码
makefile编写
利用make工具可以自动完成编译工作。
makefile完成了整个工程的编译、链接规则
target ... : prerequisites ...
command
// 待补充
信号
常见的信号,系统如何将信号通知到进程
信号是事件发生时,对进程的通知机制。通常是内核将信号通知给进程
信号通知方式:
内核在进程表项的信号域设置对应信号的位
信号发生的原因
信号发生分成三种原因:1.硬件发生异常 2.用户输入特殊字符(control c中断)(control z暂停)3. 发生了软件事件
怎么发送信号
-
用户输入
kill()方式发送信号。命令允许用户向进程发送信号
Ctrl-C发送INT信号(SIGINT);默认情况下,这会导致进程终止。
Ctrl-Z发送TSTP信号(SIGTSTP);默认情况下,这会导致进程挂起。
Ctrl-\发送QUIT信号(SIGQUIT);默认情况下,这会导致进程终止并且将内存中的信息转储到硬盘(核心转储)。
(这些组合键可以通过stty命令来修改。) -
kill用来发送信号到进程或者杀死进程
-s sig 信号名称。
-n sig 信号名称对应的数字。
-l 列出信号名称。kill -l 9 : 列出9号信号对应的名称:KILL
kill 杀死进程实际上做了什么事情
常用信号:
HUP 1 终端挂断
INT 2 中断(同 Ctrl + C)interrupt
QUIT 3 退出(同 Ctrl + \)
KILL 9 强制终止
TERM 15 终止
CONT 18 继续(与STOP相反,fg/bg命令)
STOP 19 暂停(同 Ctrl + Z)
多线程和多进程的区别
i++是否是原子操作,为什么
不是。i++操作分为三个阶段(读、改、写) 不加锁互斥是不行的
linux系统的各类同步机制
同步机制:互斥锁(mutex)、条件变量(cond)(条件变量必须与互斥锁共同使用;)、读写锁(rwlock)
linux系统各类异步机制
异步机制 - 信号(signal)
任何线程都可以向其它线程(同一进程下)发送信号;
每个线程都具备自己独立的信号屏蔽集,不影响其它线程;
线程创建时,不继承原线程的信号屏蔽集
cpu寻址
根据指令的类型判断寻址方式。存储地址的地方可能会存放寄存器号码,或者内存的直接地址or偏移地址
寄存器寻址
立即数寻址:指令的地址字段存储的就是值
内存寻址(直接寻址,基址寻址:指令中给出的偏移地址加上基址寄存器的值,变址寻址)
IO多路复用
一个进程同时处理多个IO请求
本质:使用select,poll或者epoll函数,挂起进程,当一个或者多个I/O事件发生之后,使用一个进程同时监控多个IO事件。
实现原理:用户将想要监视的文件描述符(File Descriptor)添加到select/poll/epoll函数中,由内核监视,函数阻塞。一旦有文件描述符就绪(读就绪或写就绪),或者超时(设置timeout),函数就会返回,然后该进程可以进行相应的读/写操作。
epoll
epoll是Linux特有的I/O复用函数。一个文件描述符来管理多个描述符。将用户关心的事件放到内核的一个事件列表中。
内核通过红黑树描述这些文件描述符。
epoll解决了select和poll在文件描述符集合拷贝和遍历上的问题,能够在一个进程当中监听多个文件描述符,并且十分高效。
其他问题
- Linux如何查看端口占用?
Netstat -tunlp | grep 80
Lsof -i:80 需要root权限 - Linux下程序崩溃,无法打印log,如何查看哪里出现问题?
- Linux下python 调试?pdb如何使用?
- Linux下gdb使用?
- Linux 下java debug?
1.ps -e 查看进程 pid; ps -ef 能查看父进程id
2.top -p pid 查看该进程资源占用情况;
3.ps -mp pid -o THREAD,tid,time;查看该进程下的各个线程运行时间,根据运行时间可以判断卡再哪个位置; - Printf “%x\n” tid ; 把tid转换为16进制格式;
5.jstack pid | grep tid -A 30;
打印pid进程的Java运行信息,截取带有tid线程号的行并输出其后30行的信息
// 查看端口顺序 - Lsof -i:3306 or netstat -tunlp | grep 3306 查看端口占用; 找到对应的pid 或 程序名;
- Ps -aux | grep pid or top -p pid 查看该进程的资源占用(看ppid 要用 ps -ef)