顺丰C++开发 二面 面经

1. 介绍一下你最有挑战性的项目,重点说说技术架构和你解决的核心问题

回答框架:

  • 项目背景和规模(用户量、数据量、QPS)
  • 整体架构设计(画图说明)
  • 遇到的技术难点(性能、并发、一致性)
  • 解决方案和优化措施
  • 最终效果(性能提升、成本降低)

2. 线上服务突然CPU飙升到100%,你会如何快速定位问题

答案:

定位步骤

  1. top命令找到占用高的进程PID
  2. top -H -p <PID>查看线程级CPU占用,找到问题线程TID
  3. 将TID转为16进制:printf "%x\n" <TID>
  4. 查看线程堆栈: C++程序:pstack <PID> 或 gdb attach <PID>然后thread apply all bt或用perf top -p <PID>查看热点函数
  5. strace -p <PID> -c统计系统调用,看是否频繁调用某个系统调用
  6. perf record -p <PID> -g记录性能数据,生成火焰图分析

常见原因

  • 死循环或忙等待
  • 锁竞争导致自旋
  • 频繁的系统调用
  • 正则表达式回溯
  • 算法复杂度过高

3. 说说C++的内存管理,如何排查内存泄漏

答案:

内存泄漏检测工具

  • Valgrind:valgrind --leak-check=full --show-leak-kinds=all ./app优点:详细的泄漏报告和调用栈缺点:性能损耗大(10-50倍),只能测试环境用
  • AddressSanitizer:编译时加-fsanitize=address -g优点:性能损耗小(2倍),能检测更多问题(use-after-free、buffer overflow)缺点:需要重新编译
  • tcmalloc/jemalloc:替换默认allocator,提供内存分析可以在生产环境使用提供heap profiling功能

常见泄漏原因

  • new/delete不匹配(new[]要配delete[])
  • 异常导致未释放(没用RAII)
  • 容器存裸指针,容器销毁时不会delete
  • shared_ptr循环引用
  • 第三方库泄漏

预防措施

  • 优先用智能指针(unique_ptr/shared_ptr)
  • 用RAII管理资源
  • 容器存对象或智能指针,不存裸指针
  • 定期压测和内存监控

4. 讲讲epoll的工作原理,ET和LT模式有什么区别

答案:

epoll优势

  • 没有fd数量限制(select最多1024)
  • 不需要遍历所有fd,只返回就绪的fd
  • 使用mmap共享内存,减少内核和用户空间的数据拷贝

LT模式(水平触发)

  • 只要fd就绪就会一直通知
  • 未处理完的数据下次epoll_wait还会通知
  • 编程简单,不容易丢事件
  • 类似select/poll的行为

ET模式(边缘触发)

  • 只在状态变化时通知一次
  • 必须一次性读完所有数据(循环read直到EAGAIN)
  • 性能更高,减少epoll_wait调用次数
  • 编程复杂,容易丢事件

ET模式使用要点

  • 必须配合非阻塞IO
  • 读写都要循环处理直到EAGAIN
  • 注意EPOLLONESHOT,避免多线程竞争同一个fd

示例场景

  • 高性能服务器优先用ET模式
  • 业务逻辑复杂的用LT模式,降低开发难度

5. MySQL的索引原理,什么情况下索引会失效

答案:

索引类型

  • B+树索引(InnoDB默认):叶子节点存数据,非叶子节点存索引
  • 哈希索引(Memory引擎):等值查询快,不支持范围查询
  • 全文索引:用于文本搜索

索引失效场景

  1. 使用函数或表达式WHERE YEAR(date) = 2024
  2. 隐式类型转换:字符串字段用数字查询 WHERE phone = 12345678901
  3. 前缀模糊查询LIKE '%abc'(后缀模糊可以用索引)
  4. OR条件中有未建索引的列
  5. 联合索引不满足最左前缀:索引(a,b,c),查询WHERE b=1不走索引
  6. NOT、!=、<>操作符
  7. IS NULL / IS NOT NULL(取决于数据分布)
  8. 优化器判断全表扫描更快:数据量小或选择性差

优化建议

  • 避免在索引列上使用函数
  • 使用覆盖索引,避免回表
  • 联合索引遵循最左前缀原则
  • 用EXPLAIN分析执行计划

6. 说说MySQL的事务隔离级别,分别解决什么问题

答案:

四种隔离级别

  1. READ UNCOMMITTED(读未提交):可以读到其他事务未提交的数据问题:脏读、不可重复读、幻读几乎不用
  2. READ COMMITTED(读已提交):只能读到已提交的数据解决:脏读问题:不可重复读、幻读Oracle默认级别
  3. REPEATABLE READ(可重复读):同一事务内多次读取结果一致解决:脏读、不可重复读问题:幻读(InnoDB通过MVCC和间隙锁解决)MySQL默认级别
  4. SERIALIZABLE(串行化):完全串行执行,最高隔离级别解决:所有并发问题问题:性能最差

InnoDB的MVCC

  • 通过版本链和ReadView实现
  • 每行记录有隐藏字段:事务ID、回滚指针
  • 读不加锁,写加锁
  • 解决了大部分幻读问题

实际应用

  • 大部分场景用REPEATABLE READ
  • 对一致性要求极高的用SERIALIZABLE
  • 性能优先可以用READ COMMITTED

7. 如何设计一个高并发的秒杀系统

答案:

核心挑战

  • 瞬时高并发(10万QPS+)
  • 超卖问题
  • 黄牛刷单

架构设计

客户端 → CDN(静态资源) → Nginx(限流) → 业务服务
                                        ↓
                        Redis(库存预减) → 消息队列 → 异步下单
                                                      ↓
                                                   MySQL(订单)

关键技术

  1. 前端优化:按钮置灰,防止重复点击验证码,增加刷单成本静态资源CDN加速
  2. 接入层限流:Nginx限流:limit_req_zone用户维度限流:1秒只能请求1次IP限流:防止单IP刷接口
  3. Redis预减库存:用DECR原子操作减库存库存为0直接返回,不打到数据库设置库存比实际多一点,防止超卖
  4. 消息队列削峰:请求进入Kafka/RabbitMQ消费者异步处理订单返回"排队中"给用户
  5. 数据库防超卖:乐观锁:UPDATE ... WHERE stock > 0 AND version = ?或悲观锁:SELECT ... FOR UPDATE库存分段:1000件拆成10个100件,减少锁竞争
  6. 防刷策略:风控系统识别异常行为黑名单机制人机验证

8. 说说C++的智能指针,shared_ptr的线程安全性

答案:

三种智能指针

  1. unique_ptr:独占所有权,不能拷贝只能移动零开销,和裸指针性能一样适合明确所有权的场景
  2. shared_ptr:共享所有权,引用计数管理控制块包含:引用计数、弱引用计数、删除器引用计数用atomic保证线程安全
  3. weak_ptr:不增加引用计数用于打破循环引用使用前要lock()转成shared_ptr

shared_ptr线程安全性

  • 引用计数的增减是线程安全的(atomic操作)
  • 对象本身的读写不是线程安全的,需要外部加锁
  • 指针本身的修改不是线程安全的,多线程同时赋值需要加锁

举例说明

shared_ptr<int> p = make_shared<int>(42);

// 线程安全:拷贝shared_ptr
shared_ptr<int> p2 = p;  // 引用计数原子增加

// 不安全:修改对象
*p = 100;  // 多线程需要加锁

// 不安全:修改指针本身
p = make_shared<int>(200);  // 多线程需要加锁

循环引用问题

  • A持有B的shared_ptr,B持有A的shared_ptr
  • 导致引用计数永不为0,内存泄漏
  • 解决:其中一方用weak_ptr

9. 讲讲C++的虚函数实现机制,虚析构函数为什么重要

答案:

虚函数表(vtable)

  • 每个有虚函数的类有一个vtable,存储虚函数地址
  • 对象内存布局:[vptr][成员变量]
  • vptr在构造函数中初始化,指向对应类的vtable

虚函数调用过程

  1. 通过对象的vptr找到vtable
  2. 根据函数索引找到函数地址
  3. 间接调用该函数

多继承情况

  • 多个基类有虚函数时,对象有多个vptr
  • 内存布局更复杂,可能需要指针调整

虚析构函数

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++八股文全集 文章被收录于专栏

本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。

全部评论

相关推荐

评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务