2019 社招腾讯后台开发总结一 操作系统篇

面试题型来源于网上收集的面经,答案仅供参考,如果错误,及时指正。

 

1. 进程间通信机制

         1. 共享内存

         2. 套接字

         3. 消息队列

         4. 管道

         5. 信号量

         6. 信号

2. 线程间同步手段

         1. 互斥量

         2. 条件变量

         3. 读写锁

         4. 信号量

         5. 信号

3. 进程,线程和协程的区别

         进程是程序运行的实体,是操作系统分配资源的基本单位。进程有自己独立的地址空间。线程是程序运行的一个执行流,是操作系统调度的基本单位,线程共享进程的地址空间,线程有独立的栈。协程是在用户态实现的线程,创建和调度都是在用户态运行,有自己的调度器,创建开销和调度开销要小于线程。

4.  IO复用方式

         Linux常见IO复用方式有三个:select、poll、epoll

5. 程序的内存模型

         32位操作系统进程地址空间有4G,0~3G为用户空间,3~4G为内核空间。用户空间从低地址到高地址分别为:代码段、初始化数据段、未初始化数据段、堆段、栈段。

6. 程序的编译过程

         编译四部曲:

         1. 预处理,主要处理宏定义以及导入引用的头文件。

         2. 编译,将预处理得到的文本文件翻译成汇编文件。

         3. 汇编,将汇编文件翻译成机器语言文件

         4. 链接,导入引用的动态库和静态库

7. gcc的编译参数有哪些

         -l链接库,-L库路径,-S得到汇编文件,-E得到预处理文件。等等

8. select、poll、epoll的区别

         Select底层采用数组存储文件描述符,存在以下四个问题:

         1. 单进程监听的文件描述符最大数量存在限制,32位操作系统上是1024

         2. 内核/用户态空间内存拷贝问题,select复制大量的句柄数据结构,产生巨大开销

         3.  select仅支持水平触发模式,存在重复触发风险

         4.  select返回后应用程序需要遍历整个数组,效率低。

         Poll底层采用队列存储文件描述符,因此没有文件描述符数量限制,select其它三个缺点它也有。

         Epoll解决select和poll的缺点,底层采用队列加红黑树方式实现,除了不受文件描述符数量限制之外,还支持边缘触发模式。

9. 函数参数入栈顺序

         从右向左进栈

10. 堆栈溢出的一般原因

         堆溢出一般是内存泄漏,例如手动申请内存忘记释放。栈溢出一般是递归调用层次太深。

11. 内存分配的三种方式

         主要指内存分配的位置。

         1. 静态分配,全局变量和局部静态变量属于静态分配,分配在程序的静态数据区。

         2. 动态分配,手动调用malloc这种,在堆区分配。

         3. 自动分配,系统自动分配在栈区,主要用于函数调用参数入栈和出栈。

12. fork和vfork的区别

         Fork创建子进程,返回2个值,等于0表示子进程,大于0表示父进程。子进程共享父进程的地址空间以及继承打开的文件描述符,Linux采用写时复制技术,只有当父子进程尝试修改地址空间的时候,才会触发缺页中断处理程序执行真正拷贝。

         Vfork和fork类似,也是采用写时复制技术,不过vfork保证子进程优先运行,直到子进程调用exec或者exit。

13. Fork创建子进程继承父进程打开的文件描述符,如何不让子进程继承

         可以在打开文件的时候设置FD_CLOEXEC标志位,创建子进程的时候自动关闭文件。

14. 介绍僵尸进程和孤儿进程

         僵尸进程指的是子进程退出后,父进程没有回收子进程的资源。僵尸进程过多导致系统资源不足。

         孤儿进程指的是父进程退出,子进程变成孤儿进程,孤儿进程由init进程进行资源回收。

15. 如何解决僵尸进程过多问题

         1. 可以在父进程的SIG_CHLD信号处理函数中回收子进程资源。

         2. 设置父进程的SIG_CHLD信号处理函数位SIG_IGN,子进程会自动回收。

16. 如何查看操作系统共享内存,命令是啥

         查看共享内存命令是ipcs,ipcrm

17. exit和_exit的区别

         Exit内部调用_exit,区别在于exit会额外执行三个步骤:

         1. 关闭打开的文件描述符

         2. 刷新缓冲区

         3. 执行注册的清理函数

18. 解释阻塞、非阻塞,同步和异步区别

         阻塞指的是系统调用得不到满足,进程挂起。

         非阻塞指的是系统调用得不到满足,程序立即返回。

         同步和异步主要指的是IO复制操作是否同步进行。同步也包括阻塞和非阻塞。

19. 系统调用和库函数区别

         系统调用是操作系统提供给应用程序的接口,库函数是应用程序的接口,库函数封装了大部分系统调用。

20. 调度类别和调度策略

       Linux常用两种调度类,实时类和完全公平调度类。

         实时类有两种调度策略,分别是先来先服务和时间片轮转:

         1. 先来先服务(FIFO),谁先来谁先运行,直到进程自己退出、或者执行阻塞调用让出CPU、或者被更高优先级进程抢占。

         2.     时间片轮转(RR),相同优先级的进程分配相同的时间片,采用队列方式组织,进程退出有如下几种原因,进程的时间片运行完、进程自身退出、进程执行阻塞调用让出CPU、进程被更高优先级进程抢占。

         完全公平调度类(CFS)的实现基于红黑树,每个进程分配一个动态时间片,进程退出有如下几种方式:进程的时间片运行完、进程自身退出、进程执行阻塞调用让出CPU、进程被更高优先级进程抢占。

         我们普通创建的进程就是CFS,操作系统提供了sched_setscheduler()接口用来修改进程的调度类和调度策略。

21. 惊群效应以及解决

         一组睡眠线程等待同一个资源,当资源满足的时候,操作系统唤醒所有线程争抢资源,最终只有一个线程能够抢到,剩余线程继续睡眠。此种方式涉及大量系统调用开销,没有必要。解决方式是使用锁保护加队列方式,当资源满足的时候,只唤醒第一个线程即可。Linux条件变量的实现即采用了这种方式。

22. 死锁现象、必要条件以及解决方式

         现象:线程A持有资源A,请求资源B,线程B持有资源B,请求资源A,双方互不释放拥有的资源,一直等待,此即死锁。

         四个必要条件:互斥、请求与保持、不剥夺、循环等待。

         解决方式:顺序请求资源。

        

23. 解释可重入函数

         一个函数是可重入的,是指这个函数可以重复进入自身执行而不引起任何不良后果。

         特点:不使用全局变量或者局部静态变量。不调用任何不可重入函数。

24. top命令各个参数意义,cache、buffer

         Cache主要是文件缓存,buffer主要是磁盘缓存。

25. 查看磁盘、网络、虚拟内存的命令

         Iostat查看磁盘。

         Netstat查看网络

         Vmstat查看虚拟内存

26. 介绍常用的Linux命令(awk, sed)

         自称会shell不能不懂awk和sed。Awk主要用于列处理,sed用于行处理。此外,开发常用命令包括grep搜索,wc统计,tcpdump抓包等等。

27. 守护进程概念以及创建方式

         守护进程不与任何终端关联,独自在后台运行。操作系统提供了daemon接口创建守护进程。还有一种手动创建方式,在《Linux环境编程:从应用到内核》书里有介绍。

28. 进程的七个状态

         运行态、可中断的睡眠状态、不可中断的睡眠状态、停止态、跟踪态、僵尸态、死亡态。

29. 常见信号

         SIG_CHLD,SIG_KILL, SIG_TERM, SIG_ALARM,SIG_USER1, SIG_USER2, SIG_PIPE, SIG_BUS等等,要知道自己列举的信号是干嘛的。

30. 内存泄漏怎么检查

         Linux提供了两种工具可以检测内存泄漏,valgrind和mstrace,可以没用过,但是要知道。此外就是通过top观察内存占用。

31. Linux虚拟内存的优点

         1. 提供进程独立地址空间。

         2. 提供比物理内存更大的地址空间。

         3. 还有很多,此处省略。

32. Linux内存管理机制

         Linux采用段页机制管理内存,访问内存的时候先经过分段单元转换成线性地址,然后经过分页单元转换成物理地址。此外,使用伙伴管理算法和slab算法管理内存,这里要了解伙伴关系算法和slab算法都是做啥用的。

33. 如何实现一个内存池

         先申请一块大内存,然后将大内存分割成小内存,使用队列串起来,每次申请内存直接去队列里面申请。(内存池的知识很重要,面试经常考,要懂得原理。原理和伙伴关系算法以及C++ allocator两级空间配置器类似,建议小伙伴阅读《STL源码解析》以及《深入理解Linux内核》相关章节)

34. 程序的运行流程

         通常在Linux shell下执行一个程序流程这样:shell调用fork创建子进程,子进程执行exec类调用加载新程序上下文,加载完成后开始执行新程序。

35. 管道和有名管道的区别

         无名管道只能用在有亲缘关系的进程之间,有名管道可以用在任意进程之间。这一点和无名信号量与有名信号量类似。

36. 软连接和硬链接的区别

         简单说,软连接像一个快捷方式、硬链接相当于拷贝。硬链接只能在同一个文件系统上执行,且不能对目录执行。软连接没有这些限制。

37. Linux文件类型有哪些

         7类。普通文件,目录文件,管道文件,套接字文件,链接文件,块设备文件,字符设备文件。

38. 为什么系统调用开销大于函数调用开销

         两点。

         1. 系统调用运行在内核态,用户调用运行在用户态,切换的时候要执行栈的切换以及上下文保持,可能导致硬件高速缓存失效。

         2. 系统调用特权级比较高,需要执行一系列特权级检查和参数检查。

39. 信号量的实现

         底层采用锁、计数器、队列实现。

40. 介绍Linux Swap分区

         Linux系统下的swap分区即交换区,Swap空间的作用可简单描述为:当系统的物理内存不够用的时候,就需要将物理内存中一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序。这些被释放的空间被临时保存到swap空间中,等到那些程序需要运行时,再从swap中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行swap交换。

41. 单核处理器是否需要加锁

         需要加锁,当单线程访问临界区的时候,可能被操作系统调度出去,此时其它线程就可能访问临界区,因此,需要加锁保护。

42. 缺页置换算法

         当访问一个内存中不存在的页,并且内存已满,则需要从内存中调出一个页或将数据发送至磁盘swap分区替换一个页,这种现象叫做缺页置换。

常见的缺页置换算法如下:

       1. 先进先出算法(FIFO):置换最先调入内存的页面,即置换在内存中驻留时间最久的页面。按照进入内存的先后次序排列队列,从队尾进入,队首删除。

         2. 最近最少使用(LRU)算法:置换最近一段时间以来最少使用过的页面,根据程序的局部性原理,刚被访问的页面,可能马上就要被访问。反之相反。

43. 可靠信号和不可靠信号

         可靠和不可靠信号的区别在于前者不会丢失,后者会丢失。不可靠是1~31之间的信号,底层采用的是位图的方式实现,多个相同信号只会记录依次,因此会出现信号丢失。可靠信号底层采用队列的方式实现,收到信号则在队列里添加一个元素。但是,值得注意的是,可靠信号也不是完全可靠,因为队列的容量有限,超过一定限制也会丢失,这一点在《Linux环境编程:从应用到内核》中有详细讲过。

44. 进程状态转换图

45. 定时器实现方案

         这个不一定考,我项目里面有用到定时器,所以考到了。Linux定时器的实现,网上有一篇非常好的讲解文章,建议阅读下,地址:IBM Developer

         这里给出两种方式:

         1. 基于链表和信号实现定时器。

         2. 基于时间轮 (Timing-Wheel) 方式实现的定时器,知道时间轮的大致实现就好,原理蛮简单的。

46. 非递归锁的错误码

         非递归锁会返回EDEADLK,递归锁非同一个加锁线程会返回EPERM.

47. 线程池的实现方案

         线程池的基本构成包括工作队列,任务线程以及条件变量。任务线程空闲的时候就去工作队列取任务,没有任务则等待条件变量。这个网上有很多例子,了解就好。

48. 有了线程为啥还需要进程

         1. 进程地址空间相互隔离,安全性高。线程之间一个挂掉,整个进程都会退出。

         2. 进程地址空间有限,创建的线程数有限。

         3. 进程是程序的一个实体,线程是程序的一个执行流。有很多不同的程序需要进程运行。

49. 设计无锁编程

         参考CAS(compare and swap)设计。

50. 存在依赖关系的库之间编译顺序有关系吗?

         有,存在依赖关系的库编译顺序是被依赖的放在后面。如果存在循环依赖的话,gcc有个编译选项xlinker可以解决此问题

51. 五种IO模式

         阻塞、非阻塞、IO多路复用、异步IO、信号驱动

52. 系统上电到运行init进程之间做了什么

         1. 运行上电POST自检程序。

         2. 读取MBR主引导记录。

         3. 加载bootloader最小引导系统。

         4. 加载内核。

         5. 执行init进程。

额外推荐参考书:

1. 《深入理解Linux内核》

2. 《Linux环境编程:从应用到内核》

3. 《深入理解计算机系统》

4. 《Linux环境高级编程》

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值