绿盟校招 C++ 研发工程师一面面试复盘
-
进程间通信方式中的共享内存为何比套接字快呢? 共享内存的核心是让多个进程映射同一块物理内存到各自的虚拟地址空间,通信过程完全绕开内核的中转干预。而套接字会触发用户态到内核态的切换。用户态与内核态的切换,需要保存、恢复进程上下文,这是操作系统的核心开销之一,套接字的每一次
send()/recv()都是系统调用,都要经历用户态->内核态->用户态的切换。共享内存无协议开销,数据是直接写入内存的原始字节流,无需封装任何协议头、无需计算校验和、无需处理拥塞控制,CPU 开销极低。 -
线上 CPU 飙升如何排查?
- 首先确认是哪个进程占用 CPU 过高,登录服务器利用
top命令查看各个进程的资源占用情况。 - 确认 CPU 利用率很高的进程 PID,假设 1234 为某个进程,则通过
top -Hp 1234查看具体的线程。 - 假设得到的线程 ID 是 5678,再将线程 ID 转化为十六进制,得到十六进制的 tid162e,此时利用
gdb 1234附加进程并查看具体栈信息。gdb 命令用于生成当前时刻的线程快照。线程快照是当前每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因。 - 根据堆栈信息就可以定位到具体是哪行代码导致 CPU 飙升,对应修复即可。
- 首先确认是哪个进程占用 CPU 过高,登录服务器利用
-
高并发设计,如何做限流呢?说一说你知道的限流算法 限流是限制到达系统的并发请求数,使系统能够正常的处理部分用户的请求,来保证系统的稳定性。限流的本质是因为后端处理能力有限,需要截掉超过处理能力之外的请求,亦或是为了负载均衡客户端对服务端资源的公平调用,防止一些客户端饿死。
- 计数限流:每次请求到来时候对计数器进行计数,如果超过阈值就拒绝。
- 固定窗口限流:每次请求来,计数器加一,超过阈值,拒绝访问。窗口时间到了,计数器清零。
- 滑动窗口限流:主要解决固定窗口在临界时间时,重置计数器,导致下一次窗口涌入大量请求。为每个请求增加一个到达时间,其实就是把时间作为区间记录当前区间的请求数是否小于阈值。
- 漏桶算法:水滴(请求)持续滴入漏桶中,底部定速流出(处理请求)。桶满拒绝。
- 令牌桶算法:定速往桶里塞入令牌,请求只有拿到令牌才能通过,之后再被服务器处理。桶满丢令牌。
为什么拷贝构造函数使用引用传递而不是值传递? 首先明确拷贝构造函数是 C++ 中一种特殊的构造函数,作用是:用一个已存在的同类对象,初始化一个全新的同类对象。语法原型:
// 正确写法:const 引用传递 A(const A& other);
在拷贝构造函数中使用值传递会触发无限递归,导致程序崩溃,这是最根本、最核心的原因。如果拷贝构造函数的参数写成值传递A(A other),程序编译运行阶段一定会触发无线递归,最终因栈溢出崩溃。**为什么值传递会触发无限递归?**先记住一个 C++ 铁律
C++ 中,所有函数值传递参数,在函数被调用时,编译器都会自动为这个参数创建一个临时拷贝副本
在拷贝的过程中,不是简单的内存复制,而是严格调用对应类型的拷贝构造函数来完成的。假设我们把拷贝构造函数写成值传递版本:
class A {
public:
// 错误写法:拷贝构造函数 采用 值传递
A(A other) {
// 构造逻辑
}
};
当我们在代码中,尝试用一个已存在的 A 对象 a1,创建新对象 a2 时:A a2(a1);,会触发如下无限循环的调用过程:

