通用技术面试题汇总
Categories: 面试 / 计算机基础
一. Linux系统
1. Linux下IO模型有几种,各自的含义是什么
阻塞IO:当一个进程发起IO请求时,如果数据未准备好,进程会被阻塞,直至操作完成
非阻塞IO:发起IO请求时进程不会被阻塞,如果数据未准备好,会立即返回一个错误(通常是EAGAIN或者EWOULDBLOCK),告知进程稍后再试
注意:阻塞是文件的特性,不是read/write函数的特性。socket,pipe这类文件是默认阻塞io,而普通文件是非阻塞io
IO多路复用:通过使用select,poll,epoll等系统调用,单个线程可以监听多个fd上的事件,让os内核检测绑定到其(io复用函数)上的fd读写事件来告诉用户某个fd是否可以进行IO操作
异步IO:进程发起I/O请求后,可以立即继续执行其他任务,而无需等待I/O操作完成。I/O完成后,系统会通过回调函数或信号等方式通知进程。
io_uring:是Linux内核中异步I/O框架,引入于较新的内核版本。它通过使用环形缓冲区(ring buffers)在用户态和内核态之间高效地提交和完成I/O请求
2. epoll和poll有什么区别
使用epoll_wait调用完成后,可以直接在events参数中拿到所有有事件就绪的fd,直接处理即可,是一个出参。而poll函数的事件集合调用前后大小未改变,只是通过pollfd的event参数设置我们关心的事件,通过检查revent得到就绪的事件。
3. 用一行命令查看文件的最后五行
tail filename -n 5tail -f实时监控文件,tail -f原理是检测文件大小
4. 用一行命令输出正在运行的java进程
ps aux | grep java | grep -v grep-v反向过滤
5. 介绍下你理解的操作系统中线程切换过程
保存当前运行线程的状态(上下文), 包括寄存器:PC,堆栈指针SP,通用寄存器;程序状态字:包含CPU状态,线程优先级等;内存管理信息:页表指针等
更新线程的状态为就绪or阻塞,cpu时间片用完则更新为就绪态,因为等待io则为阻塞态。
调度器根据调度算法选择下一个要运行的线程。常见调度算法:先来先服务,短作业优先,优先级调度,时间片轮转,多级反馈队列
加载新线程的上下文,将被选中线程的上下文从其存储位置(如内核栈或线程控制块)加载到CPU寄存器中,包括PC,SP,其他通用寄存器和状态字。
更新内存管理单元MMU。如果新线程属于不同进程,可能需要更新MMU,如页表基地址寄存器,以确保新线程的虚拟地址空间能正确映射到物理内存。
CPU开始执行新线程的指令,切换过程结束
6. 进程和线程的区别
进程是os分配资源的基本单位,而线程是os调度的基本单位
进程之间内存和资源(fd)是相互隔离的,而同一个进程内所有线程共享进程的资源
进程创建/销毁开销大,需要分配独立的地址空间,资源和PCB。线程的创建/销毁开销比进程小,因为线程共享进程的地址空间和资源。
上下文切换开销,进程大,线程小。
IPC通信较复杂,通过管道(pipe,fifo),消息队列,共享内存,信号,本地套接字。线程通信相对简单高效,同一进程内的线程共享内存,可以通过共享变量、全局数据结构等方式进行通信,效率更高,但需要注意同步和互斥问题
一个进程崩溃后,不会影响其他进程,而一个线程崩溃后可能导致整个进程结束,一般来说,每个线程都是独立执行的单位,每个线程都有自己的上下文堆栈,一个线程的崩溃不会对其他线程造成影响。但是通常情况下,一个线程崩溃会产生一个进程内的错误,例如在Linux操作系统中,可能会产生一个Segment Fault错误,这个错误会产生一个信号,操作系统默认对这个信号的处理就是结束进程,整个进程都被销毁了,这样的话这个进程中存在的其他线程自然也就不存在了。
7. top 命令之后有哪些内容,有什么作用
8. 线上CPU爆高,请问你如何找到问题所在
top/htop, 按P按cpu利用率进行排序
使用strace跟踪系统调用strace -p perf、vtune,火焰图等工具可以进行更深入的性能分析,找出CPU热点函数,确认是否存在无限循环或低效的算法,确认是否存在锁竞争、死锁等问题,导致线程频繁切换或忙等待。
9. 进程间通信机制有哪些,各自的优缺点是什么
pipe:优:管道的实现和使用相对简单,适合简单的数据传输需求。在同一台机器上的进程间传输数据时,管道的性能较好。缺点:标准管道只能实现单向数据传输,0读1写,如果需要双向通信,需要创建两个管道;只能用于具有亲缘关系的进程之间,无法在任意两个进程间使用;管道的缓冲区有限,当缓冲区满时,写入操作会被阻塞,影响性能。
fifo命名管道,可以在没有亲缘关系的任意两个进程之间进行通信。FIFO在文件系统中以文件的形式存在。
优:任何进程,只要知道FIFO的路径,都可以进行通信
消息队列:单条消息的大小受到限制,传输大数据时需要分割处理;需要处理消息的发送和接收同步,避免消息丢失或重复处理。
共享内存:需要额外的同步机制(如信号量、互斥锁)来管理对共享内存的并发访问,防止数据竞争和不一致。
信号量
信号:信号只能传递有限的信息(通常是信号编号),无法传递复杂的数据;信号可能被忽略或覆盖,无法保证所有信号都会被接收和处理;
本地套接字
二. 多线程
1. 多线程的几种实现方式,什么是线程安全
线程安全指多个线程在并发访问共享资源时,不会导致数据不一致或出现竞态条件,程序的执行结果与单线程执行结果相同。实现线程安全:mutex,cv,rw_lock, atomic, TLS(线程局部存储)
2. volatile的原理,作用,能代替锁么
volatile是一个类型修饰符,用于指示编译器该变量可能在程序的任何时刻被意外地修改,防止编译器对访问该变量的代码进行优化。确保每次对volatile变量的访问都发生实际的内存读取或写入,避免编译器将其优化为常量或寄存器中的缓存值。
编译器优化会假设程序没有未定义行为,两个线程同时访问同一个数据会产生数据竞争,这是未定义行为。
3. 线程的生命周期状态图
新建->就绪->运行->等待/阻塞->终止
4. sleep和wait的区别
sleep:
- 暂停执行:线程在指定的时间内不执行任何操作,进入休眠状态。
- 不释放锁:如果在持有互斥锁的情况下调用
sleep,锁依然被持有。 - 时间控制:基于时间的暂停,适用于定时任务或延时操作。
- 不可被唤醒:线程只能在指定时间到达后自动恢复执行,无法通过其他线程的操作唤醒。
wait:
- 条件等待:线程在等待某个条件满足后才继续执行。
- 释放锁:调用
wait时,线程会自动释放持有的互斥锁,进入等待状态。 - 可被唤醒:其他线程可以通过
notify_one或notify_all唤醒等待的线程。 - 与互斥锁结合使用:通常与
std::mutex一起使用,确保对共享资源的安全访问。
三. CPP 基础
1. 深拷贝和浅拷贝区别
2. 同步机制的wait和notify
wait在条件不满足的时候释放锁,等待条件改变。另一线程改变了条件后利用notify通知等待该条件的线程。
wait要配合mutex一起使用,且保证释放锁进入等待是一个原子操作。假设不是原子的,在释放锁后还未进入等待前,其他线程得到锁,可以修改条件,进而通知,而当前线程还未进入等待状态,因此会错过这次通知,如果后续没有新的通知,该线程会一直阻塞下去。
3. static 关键字是干什么用的?
- 修饰全局变量和函数
- 修饰类的成员变量和函数
- 修饰局部变量
4. final 关键字是干什么用的?
确保子类中重写父类虚函数时函数签名保持一致,也表明这是一个重写函数,增加可读性。
5. 重写和重载的区别
四. 网络
1. TCP三次握手和四次挥手的流程
2. 为什么断开连接要4次?
保证数据能够处理完
3. 如果握手只有两次,会出现什么?
之前的重复连接初始化,比如一个client发起连接,发送syn报文,但由于网络原因,迟迟未到达,client又重新发起了一次连接,而之前的syn报文在新报文之前到达,server会回复第一个的syn的ACK+SYN,client收到后发现server确认的syn是之前的,由于只有两次连接,也不会发RST报文让server终止该链接,造成的资源的浪费。
4. TIME_WAIT和CLOSE_WAIT的区别
5. 说说你知道的几种HTTP响应码
比如200, 302, 404。200=OK,302
6. 当你用浏览器打开一个链接(http://www.baidu.cn)的时候,计算机做了哪些工作步骤
1. url解析,将其拆解为协议,域名还有路径
2. DNS解析,首先检查本地DNS缓存中是否已经有该域名的ip地址。如果本地缓存没有或者缓存过期,浏览器会向DNS服务器发起请求
3. 得到IP地址后,建立TCP连接,三次握手
4. 发起http请求
方法 URL 版本\r\n
请求头\r\n
\r\n
请求体\r\n
5. 服务器处理请求,通过\r\n\r\n分割请求头和请求体,然后利用\r\n分割每一行,回复http response
状态行:包括HTTP版本、状态码(如200、404等)和状态消息(如OK、NotFound等)。例如: HTTP/1.1 200 OK
响应头(Headers):包含响应的元数据,如内容类型(Content-Type)、内容长度(Content-Length)和服务器信息(Server)等。
响应体(Body):包含服务器返回的实际数据,比如HTML文档、图片或其他类型的文件。
6. 浏览器接收到响应,检查响应状态码,例如 200 OK 表示请求成功,404 Not Found 表示页面不存在。
7. 浏览器解析 HTML 文档并开始渲染页面
8. 如果 HTTP 协议启用了 Keep-Alive,浏览器和服务器会复用同一个 TCP 连接进行其他请求,避免重新建立连接。
如果 Keep-Alive 未启用或所有请求完成后,TCP 连接会被关闭。7. 如何避免浏览器缓存
通过设置服务器的 HTTP 响应头来控制缓存行为:
Cache-Control:
Cache-Control: no-cache:告诉浏览器每次都必须向服务器验证是否有新内容,而不直接使用缓存。
Cache-Control: no-store:禁止浏览器和中间缓存保存响应数据,每次请求都会重新获取。
Cache-Control: max-age=0:设置缓存过期时间为 0,浏览器会立即过期此内容并验证更新。
Expires:
Expires: 0:设置缓存过期时间为 0,相当于立即过期。通常搭配 Cache-Control 使用。8. HTTPS的加密方式是什么,讲讲整个加密解密流程
客户端选择一个随机数,将随机数和自己支持的加密算法发送给服务端
服务端选择一个加密算法和计算一个随机数,加上自己的CA(证书)发给客户端
客户端验证CA的合法性,若合法计算一个pre-master(随机数),采用CA中的公钥加密,发送给服务端。同时通过两个随机数+pre-master和加密算法计算出会话秘钥
服务端用自己的私钥解密,得到pre-master,进而通过随机数和加密算法计算出会话秘钥,回复一个ACK确认之后的通话使用会话秘钥五. 架构
1. 后台系统怎么防止请求重复提交
a. 设置唯一请求id,每个请求携带一个唯一的标识符(如UUID)。服务器在处理请求前,先检查该ID是否已被处理过,若已处理则忽略或返回之前的结果。
b. 在服务器端,通过检查请求的特征(如参数、IP、时间戳等)来判断是否为重复请求
2. 如何做到接口的幂等性
幂等:指同一个操作执行多次,产生的效果与执行一次相同
3. 如何做限流策略,令牌桶和漏斗算法的使用场景
a. 令牌桶算法(Token Bucket)
原理:
- 令牌桶中按固定速率生成令牌,存储在桶中。
- 每次请求到来时,需消耗一个令牌,若桶中有令牌则允许请求,通过;若无令牌,则拒绝或排队。
- 令牌桶允许短时间内的突发流量,因为桶中可以存储一定数量的令牌。
实现步骤:
- 令牌生成:按固定速率(如每秒生成N个令牌)向令牌桶中添加令牌。
- 请求处理
- 请求到来时,检查令牌桶中是否有令牌。
- 如果有,取出一个令牌,允许请求通过。
- 如果没有,根据策略(拒绝或排队)处理请求。
b. 漏桶算法(Leaky Bucket)
原理:
- 漏桶以固定速率”漏”出请求,模拟水从桶中流出。
- 请求到来时,如果桶中有空余空间,则将请求放入桶中;否则,拒绝请求。
- 漏桶保证请求以固定速率处理,防止瞬时高流量导致系统过载。
实现步骤:
- 请求进入:每个请求尝试放入漏桶。
- 请求处理
- 漏桶以固定速率处理请求,模拟”漏出”。
- 若桶已满,拒绝新请求。
4. 服务如何容灾,服务故障,单机故障等
容灾:冗余部署,数据备份,自动故障转移
5. 谈谈你知道的设计模式
六. MYSQL
1. 数据库隔离级别有哪些,各自的含义是什么,MYSQL默认的隔离级别是什么
串行化:事务串行执行
可重复读:在一个事务中,同一个查询的结果一致。【默认】
读提交:事务可以看到已提交事务的更改
读未提交:事务可以看到未提交事务的更改2. 什么是幻读
同一个事务中两次读取同一个范围,看到了上一次读取时未有的数据
解决幻读:间隙锁,锁住数据之间的间隙,其他事务不能插入。行+间隙=nextKeyLock3. MYSQL有哪些存储引擎,各自优缺点
MYISAM: 不支持行锁,不支持事务,只支持表级锁,并发度低,只有binlog没有redolog,没有crash-safe。
INNODB:支持行锁,支持事务,有redolog,4. 高并发下,如何做到安全的修改同一行数据
5. 乐观锁和悲观锁是什么,INNODB的标准行级锁有哪2种,解释其含义
6. SQL优化的一般步骤是什么,怎么看执行计划,如何理解其中各个字段的含义
explain 查询语句
possiblekey:可以选择的索引
key: 实际选择的索引
type: 查询类型,ALL代表全表扫描7. 数据库会死锁吗,举一个死锁的例子,mysql怎么解决死锁
# Session1
begin;
select * from t where id = 1 for update;
select * from t where id = 3 for update;
# Session2
begin;
select * from t where id = 3 for update;
select * from t where id = 1 for update;
解决死锁:通过死锁检测,终止掉一些事务8. MYSQL的索引原理,索引的类型有哪些,如何创建合理的索引,索引如何优化
9. 聚集索引和非聚集索引的区别
10. select for update 是什么含义,会锁表还是锁行或是其他
11. 为什么要用Btree实现,它是怎么分裂的,什么时候分裂,为什么是平衡的
12. 数据库的ACID是什么
13. 某个表有近千万数据,CRUD比较慢,如何优化
用到复合索引