校招后端面经——Linux

校招后端面经--Linux

        • 1. Linux二进制文件格式
        • 2. Linux动态库的加载
        • 3. 文件系统
        • 4. 进程
          • 1. 孤儿进程
          • 2. 僵尸进程
          • 3.守护进程
        • 5. 相关命令
          • linux系统很卡的基本排查方法
        • 6. 进程间的通信
          • 1. 管道
          • 2. 消息队列
          • 3. 共享内存
          • 4. socket
          • 5. 信号量
        • 7. gdb调试
        • 8. 协程
          • 1. 定义
          • 2. 机制
          • 3. 优势
        • 9. Linux开机启动过程

Linux考察点很多,本人目前了解的比较浅,凑合着整理了。

内核分为 进程管理系统 、 内存管理系统 、 I/O管理系统 和文件管理系统 四个子系统

1. Linux二进制文件格式

ELF格式

2. Linux动态库的加载

根据这个博客整理

  1. 可执行文件和动态库是elf的形式,elf的头部是被加载到偏移量为0的进程空间上,elf头部存放着program header的偏移量。
  2. 对于一个exe程序,启动的时候,通过系统调用exec()函数把当前进程的内容替换为要加载的应用程序,从而进入内核,但内核需要知道程序的执行入口地址(注意,这里不是进程的起始地址),而执行入口地址由program header提供,当前内核只知道进程的起始地址,不知道执行的入口地址。
  3. 因此内核先去elf文件中根据偏移量找到program header的地址,再从program header的地址找到入口地址。
  4. 先启动动态连接器,加载程序所依赖的库。库是存放在动态区中,动态区的地址也是存放在elf文件中,找到动态区后加载动态区上的库的列表中库
  5. 接着动态连接器重新分配地址。在编译阶段,连接器是不知道动态库中的变量和函数的地址的。这个时候,连接器把变量和函数符号放到PLT(过程连接表)里面,这个表在运行中只可读,这样就可以在运行的时候知道这些变量和函数的地址了。
  6. 运行的时候,程序不会直接去查这个表,而是通过GO表(全局变量偏移表)找到对应的地址。每次程序使用动态库里的函数和变量的时候,就会向GO表去取 ,这个操作在编译阶段就已经形成。

3. 文件系统

  1. 在Linux系统中,以 文件 方式访问设备 。

  2. Linux文件系统使用索引节点来记录文件信息,索引节点是一个数据结构,它包含了一个文件的文件名,位置,大小,建立或修改时间,访问权限,所属关系等文件控制信息,一个文件系统维护了一个索引节点的数组,每个文件或目录都与索引结点数组中的唯一一个元素对应,系统为每个索引结点分配了一个号码,也就是该结点在数组中的索引号,称为索引结点号。 Linux文件系统将文件索引结点号和文件名同时保存在目录中,所以目录只是将文件的名称和它的索引结点号结合在一起的一张表。目录中每一对文件名称和索引结点号称为一个连接。

  3. 文件共享时链接方式分为: 硬链接 和 符号链接

    硬链接:两个文件目录都存储文件名和对应文件的索引号,并设置一个计数器,每共享到一个目录就加1,当计数器为0时,删除文件

    符号链接:B如果要共享A中的文件F的话,B目录创建一个文件F,B中的文件F上面记录A中F文件的路径,B通过路径访问A中的F文件

4. 进程

1. 孤儿进程

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

2. 僵尸进程

一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

3.守护进程

是指在Linux或其他多任务操作系统中在后台执行的电脑程序,并不会接受电脑用户的直接操控。此类程序会被以进程的形式初始化。守护进程程序的名称通常以字母“d”结尾。不继承标准输入,继承标准输出(nohup命令,fg,bg)

5. 相关命令

https://www.cnblogs.com/hystj/p/8552757.html (尤其是进程和awk命令)

linux系统很卡的基本排查方法
  1. free -g :查看内存使用情况
  2. df -h :查看磁盘使用情况
  3. iostat -x 1 :查看磁盘IO使用情况(1表示1s刷新一次)
  4. top : 查看CPU使用情况,实时显示系统中各个进程的资源占用状况,可以按CPU使用.内存使用和执行时间对任务进行排序

6. 进程间的通信

1. 管道

管道通信,在一个进程之中,只能单一的对其写或者是读,而不可以及执行写操作又执行读操作。

利用系统调用pipe()创建一个匿名管道文件,通常称为匿名管道或PIPE;利用系统调用mknod()创建一个命名管道文件,通常成为有名管道或者FIFO。PIPE是一种非永久性的管道通信机构,当访问的进程全部终止时,它也将随之被撤销;它也不能用于不同族系的进程之间的通信。而FIFO是一种永久性的管道通信机构,它可以弥补PIPE的不足。管道文件被创建之后,使用open()将文件进行打开,然后便可以对它进行读写操作,通过系统调用write()和read()来实现。通信完毕后,可使用close()关闭管道文件。因为匿名管道的文件是内存中的特殊文件,而且是不可见的,命名管道的文件是硬盘上的设备文件,是可见的。

2. 消息队列

与命名管道相比:消息队列的优势在于,它独立于发送和接收进程而存在,这消除了同步命名管道的打开和关闭时可能产生的一些困难。消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。而且,每个数据块被认为含有一个类型,接收进程可以独立地接收含有不同类型值的数据块

3. 共享内存

访问共享内存区域和访问进程独有的内存区域一样快,并不需要通过系统调用或者其他需要切入内核的过程来完成。同时它也避免了对数据的各种不必要的复制。

特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问,例如前面说到的信号量。

4. socket

见上面的网络IO

5. 信号量

7. gdb调试

l:查看源代码

b:加断点

r:开始运行调试

n:下一步,不会进入子函数

s:下一步但会进入子函数

p:输出数据

8. 协程

1. 定义

协程是一种用户态的轻量级线程

如果将程序分为IO密集型应用和CPU密集型应用,二者的server的发展如下:

IO密集型应用: 多进程->多线程->事件驱动->协程

CPU密集型应用:多进程–>多线程

2. 机制

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

3. 优势

最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

9. Linux开机启动过程

详见https://www.cnblogs.com/codecc/p/boot.html ,根据该博客整理

img

你可能感兴趣的:(面经)