Skip to content

Interview questions

System

  • 进程和线程区别
  • 进程资源分配的基本单位:有自己独立的:虚拟地址空间,打开的文件描述符、全局变量、堆
  • 线程运行在进程里面,共享进程的大部分资源,只有自己的栈、寄存器、线程局部存储
  • 线程更加轻量, 成本 更低
  • 什么是死锁,死锁的必要条件

线程 A 拿着锁 L1 等锁 L2,线程 B 拿着锁 L2 等锁 L1。

  1. 互斥条件(Mutual Exclusion)
  2. 占有并等待条件(Hold and Wait)
  3. 不可剥夺条件(No Preemption)
  4. 循环等待条件(Circular Wait)
  • 进程间通信方式
  • Pipe, Socket, 消息队列,共享内存,信号量 / 互斥锁,signal
  • linux系统里面是怎么设计内存分配器的?

用户态: malloc -> 调用 brk/mmap

内核态: kmalloc(小块 + 物理连续;用 SLAB/SLUB 分配器,再向 伙伴系统 要页), vmalloc(大块 + 只虚拟连续)

页分配器 (Buddy System)

当程序需要分配一大块连续的物理内存时,如果空闲内存分散成许多小块,即使总和足够,分配也会失败。这被称为外部碎片。Buddy System 必须确保大块内存能够被有效保留或恢复。

Buddy System 通过其独特的结构,使得空闲的内存块在释放时可以高效且快速地与相邻的“伙伴”块合并 (coalesce) 成一个更大的连续内存块。

Slab 分配器

要解决的问题:内部碎片 (Internal Fragmentation) 和分配开销 (Overhead)

Slab 分配器会为每种内核对象类型(如 inode 结构体)维护一个专门的 缓存 (Cache)。这个缓存中预先分配了许多大小恰好的内存块(Slabs),并对其中的对象进行了预先初始化

  • 内存里的有序索引一般使用什么数据结构?

  • 存在一个redis服务器集群,现在向集群中新增一个节点,怎么做数据迁移?

  • 使用链表管理共享内存分配,如果一个进程A申请了一块新的内存,结果进程A挂了,怎么回收这块内存?

  • 介绍一下leveldb的核心数据结构

  • 你在linux上是怎么调试程序的?gdb使用?gdb是怎么查看string值

  • linux中的虚拟内存?

  • linux中为什么是三级页表?

  • TLB的作用?

  • 中断为什么要分上半部和下半部?还有别的考虑吗?提示一下,考虑函数可重入性

  • 你是怎么测试系统吞吐的?

  • 你是怎么找到系统瓶颈的?

  • 为了获取更好的程序性能,你做过数据预取、SIMD等计算机体系结构相关的优化吗?

  • 讲一下CPU流水线

  • CPU进行矩阵按行遍历/按列遍历的性能差距有多少

  • 介绍存算架构

  • 讲一下CPU的cache line

CPU 不直接一字节一字节、甚至不是一整块数组地搬数据,而是按 固定大小的块 来搬,这个块就是 cache line。通常是 64 字节。你访问某个地址 p,CPU 实际会把 p 所在的那一整条 cache line读进 cache

  • cache一致性协议

每个核都有 自己的 L1/L2 cache, 但大家 共享同一块物理内存

  • write-through(直写):每次 CPU 写 cache 的同时也写内存
  • write-back(回写):写只改 cache,把 cache line 标记为 “脏(dirty)”,等这条 line 被换出时再写回内存

MESI 是目前最常见的缓存一致性协议之一

M (Modified):已修改(脏),只有一个 cache 有它,内存是旧的

E (Exclusive):独占,内容和内存一样,只有一个 cache 有它

S (Shared):共享,内容和内存一样,可以在多个 cache 里同时存在

I (Invalid):无效,这条 line 在这个 cache 里不能用了

任何一个核要从内存拿数据,都得通过总线发一个“读事务”,这个读事务在 MESI 里就记为 BusRd

  • 如何对性能瓶颈进行优化的?

  • 如果没有占比较大的算子,你如何进行优化?

  • 内核态和用户态的区别?什么情况会陷入到内核态?

  • 有一个文件描述符,向offset=3kb处写入4MB数据,操作系统中会发生什么?

  • 主存的读写时延是多少?cache 的读写时延是多少?

  • 讲一下 page cache

  • 什么情况下使用 page cache?什么情况下使用 direct io?

  • 讲一下图数据库和关系型数据库的区别

  • 系统中线程上下文开销比较大,如何解决这个问题?

  • 讲一下 redis 为什么高性能?

  • 系统调用是如何实现的?linux 有哪些常见的系统调用?

  • kafka相比于普通的生产者消费者的优势是什么

  • 根据用户名查询权限列表时很慢,怎么排查慢SQL原因以及解决方案

  • 你知道虚拟内存吗?好处是什么?每个页的大小一般是多少?

Network

  • TCP三次握手
  • 滑动窗口协议
  • TCP释放连接中的2TSL的作用是什么
  • 怎么修改UDP协议,实现可靠传输?

C++

  • 虚函数的用处,实现原理
  • weak_ptr和shared_ptr的区别,shared_ptr的实现原理
  • shared_ptr在什么情况下会造成内存泄漏?
  • 基类的析构函数要加virtual关键字吗?不加virtual会有什么后果?
  • C中的static关键字
  • C语言中,数组和指针的关系是什么?定义int A[10],如何不使用size/宏遍历数组?sizeof(A)是多少?
  • 熟悉多线程编程吗?锁有哪几种?怎么实现的?
  • C++ 11相比C++ 98新增加了哪些特性?
  • STL中的 unordered_map 和 map 有什么区别?
  • 知道右值引用吗?
  • 对异步编程了解吗?
  • 讲一下C++的多态
  • 讲一下编译的过程
  • 讲一下静态链接和动态链接
  • C++类中默认创建的函数有哪些?
  • 什么情况下要用到拷贝构造函数
  • 一个class里面,模板函数可以是虚函数吗?
  • 为什么模板函数体要放在.h文件里面?
  • 栈上分配内存和堆上有什么区别?
  • 讲一下IO多路复用,epoll原理?
  • 增加删除元素,哪几种数据结构的迭代器不失效?
  • hash table 冲突解决方法
  • 讲一下 C++ memory 模型中的 release
  • C++ 用过哪些开源的网络库?
  • 介绍一下 RabbitMQ
  • 网卡的混杂模式
  • TCP 之前的端口被占用,TCP 怎么还有链接
  • 假设一个类继承了有虚函数的类,父类会存在在子类中吗?
  • 虚表里除了可能有虚函数,还可能有什么?

Coding

  • LRU
  • 手写 shared_ptr
  • 待排序数据放在磁盘中,内存容量比较小,怎么对数据进行排序?
  • 磁盘中有1TB数据,内存大小为4GB,如何对数据去重?估计运行时间是多少?
  • 三个线程,线程1打印a,线程2打印b,线程3打印c。如何做到顺序打印a,b,c
  • 写题:根据cas执行,写无锁list
  • 在一大块连续内存上实现 hash map,主要实现出来 set(key, value) 函数
  • 手撕题:找出两个有序数组的中位数
  • 交易场景下,1s下单不能超过100笔,系统调用超过100笔,做拦截该如何实现?
  • 手撕:实现日期类,要求支持两个日期相减