微派 c++软件开发 一面 面经
1. 堆和栈的区别是什么?
- 栈由编译器自动管理,存放局部变量、函数参数、返回地址,空间有限(一般几 MB),分配和释放速度极快
- 堆由程序员手动管理,通过 malloc/new 申请,空间大(受物理内存限制),但分配释放开销更大
- 栈是连续内存,向低地址增长;堆是离散内存,由内存分配器管理
- 栈上的对象生命周期随函数结束自动销毁;堆上的对象需要显式释放,否则造成内存泄漏
2. TCP 三次握手的过程是什么?为什么不能是两次?
过程:
- 第一次:客户端发送 SYN,进入 SYN_SENT 状态
- 第二次:服务端收到后回复 SYN+ACK,进入 SYN_RCVD 状态
- 第三次:客户端回复 ACK,双方进入 ESTABLISHED 状态
为什么不能是两次:
- 两次握手只能确认客户端到服务端的通路正常,无法确认服务端到客户端方向
- 三次握手让双方都能确认自己的发送和接收能力均正常
- 同时可以防止历史失效的连接请求被服务端误认为新连接,造成资源浪费
3. malloc 的底层实现机制是什么?
- 小块内存(通常 < 128KB):通过 brk/sbrk 系统调用移动堆顶指针扩展堆空间,glibc 内部用空闲链表(bin)管理,减少系统调用次数
- 大块内存(>= 128KB):通过 mmap 直接映射匿名内存,释放时 munmap 归还操作系统
- 内部按大小维护多个 bin,分配时优先从合适的 bin 中复用空闲块,找不到再向 OS 申请
- 频繁分配释放不同大小的内存会产生内存碎片,是 malloc 的主要问题之一
4. 有 1 万个下载任务,单进程如何合理分配线程数?
- 下载属于 I/O 密集型任务,线程大部分时间在等待网络响应,CPU 占用低
- 线程数不是越多越好,过多会导致内存占用高(每个线程默认栈约 1~8MB)、上下文切换频繁
- 经验公式:线程数 = CPU 核心数 × (1 + 等待时间 / 计算时间),I/O 密集型可适当放大倍数
- 实际做法是用线程池(如 100~500 个线程)配合任务队列,1 万个任务排队分批消费
- 更优方案是异步 I/O(epoll + 协程),用少量线程处理大量并发,避免线程膨胀
5. 进程间通信有哪些方式?各自适用场景是什么?
- 管道(pipe):适合父子进程间单向通信,简单但只能传字节流
- 消息队列:支持结构化消息,解耦发送和接收方
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++八股文全集 文章被收录于专栏
本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。
