八股-2025.10.11
1.C++ 的多态机制与虚函数实现原理
当用基类指针或者引用调用同名函数时,能自动根据指针/引用指向的“对象实际类型”,匹配对应的子类实现,而不是由指针本身的类型决定。而实现这一切,底层完全依赖“虚函数”以及配套的“虚表”和“虚指针”结构。
实现多态分为两步:
a.编译期:编译器会为含虚函数的类做两项关键处理
一是为每个“有虚函数的类”生成一张独立的虚表。虚表本质是一个“函数指针数组”,专门存该类所有虚函数的地址。子类的虚表,会优先继承基类的虚表结构(保证虚函数索引位置不变),再使用子类虚函数地址覆盖掉原来基类虚函数的地址;如果子类新增加虚函数,就追加到虚表末尾。
二是为每个“含虚函数的类的对象”偷偷插入一个“虚指针(vptr)”。这个vptr是对象的隐藏成员变量,通常在对象内存对象的开头,它的值就是“当前对象所属类的虚表首地址”。
b.运行期:当用基类指针/引用调用虚函数时,会按三个步骤找到正确的函数:
先通过基类指针拿到指向对象的vptr。再通过vptr,找到对象所属类的虚表。最后根据虚函数在虚表内的“索引位置”,找到对应的函数地址并调用。
https://www.bilibili.com/video/BV1TF411h7k6/?spm_id_from=333.337.search-card.all.click&vd_source=3abe3667e67749032f72d6f512b2a967
2.讲一下乐观锁和悲观锁。
A.悲观锁认为“冲突一定会发生”,所以提前加锁阻塞并发。
a.优点:
实现简单,直接依赖成熟的锁机制,无需手动处理冲突。
数据库安全性高,提前加锁保证原子性,不会出现“脏写”“数据不一致”等问题。
b.缺点:
性能损耗高,锁的获取和释放会带来上下文切换,且未拿到锁的线程会阻塞等待,并发高时会导致“线程排队”,吞吐量下降。
可能引发死锁,若锁的释放逻辑异常(如线程宕机未释放锁),会导致其他线程永久阻塞,需额外处理死锁(如设置锁超时和定时释放)。
c.适用场景:
并发冲突概率高的场景(秒杀系统扣库存或金融交易对账),因为冲突频繁,悲观锁提前加锁能减少“重试开销”。
对数据一致性要求极高的场景(如银行转账),不允许任何并发修改导致的错误,必须通过锁确保操作独占。
d.常见实现方式:
数据库层面:MySQl中的行锁,表锁。
编程语言层面:JAVA的synchronized关键字,ReentranLock类。
分布式层面:基于Redis实现的分布式锁,ZooKeeper分布式锁。
B.乐观锁认为“冲突大概率不会发生”,所以先操作再校验冲突。
a.优点:
性能高,无锁机制,不会阻塞线程,也没有锁的上下文切换开销,高并发下吞吐量比悲观锁高。
无死锁风险,不依赖锁机制。
支持高并发,适合大量“读多写少”的场景,读操作不阻塞,写操作仅在冲突时重试。
b.缺点:
重试开销:若冲突频繁,会导致线程反复重试,浪费CPU资源。
实现复杂:需手动处理“冲突重试”逻辑(重试次数,重试延迟),且无法解决“ABA问题”。
无法解决“写饥饿”问题,若某线程一直重试失败,可能导致“写操作一直延迟”。
c.适用场景:
并发冲突概率低的场景,(如用户资料修改和商品详情页点击量统计),冲突少,重试开销小,,性能优势明显。
读多写少的场景(如电商商品详情查询),乐观锁允许读操作无阻塞,大幅提升吞吐量。
分布式系统避免“分布式锁开销”的场景(如分布式缓存更新),无需竞争分布式锁,通过版本号校验即可实现安全更新。
d.常见实现方式:
版本号机制:给共享资源加一个“版本号字段”,每次修改资源时,版本号+1。
CAS机制:乐观锁的底层实现原理,核心逻辑是“先比较资源当前值是否等于预期值,若等于则交换为新的值,否则失败”,整个操作是原子性的。
https://www.bilibili.com/video/BV1ff4y1q7we/?spm_id_from=333.337.search-card.all.click&vd_source=3abe3667e67749032f72d6f512b2a967
3.MySQL 中的 MVCC 是什么?Read View 在 MVCC 中如何工作?如果没有 MVCC 会怎样?
A.MVCC是InnoDB存储引擎实现高并发读写的核心机制,其核心思想是通过维护数据的多个版本,让读写操作和读操作能并发执行,互不阻塞,从而在保持数据一致性的同时提升系统吞吐量。
a.实现原理:
依赖三个关键组件:
隐藏列:InnoDB为每张表的每条记录添加了三个隐藏列(用户不可见);
- DB_TRX_ID:创建或最后修改该记录的事务 ID(6 字节);
- DB_ROLL_PTR:回滚指针(7 字节),指向该记录的上一个版本(存储在 undo 日志中);
- DB_ROW_ID:若表没有主键,InnoDB 会自动生成该列作为隐含主键(6 字节)。
undolog:存储历史版本
当事务修改记录时,InnoDB不会直接覆盖旧纪录,而是生成记录的新版本,并将新版本的DB_TRX_ID设为当前事务ID。将旧版本的记录写入undolog,新版本的DB_ROLL_PTR指向旧版本在undolog中的位置,形成一条版本链。
Read VIew:判断版本可见性
Read View是事务执行查询时生成的“可见性规则集合”,用于判断当前事务中能看到版本链中的哪些记录。包含四个核心参数:
- m_ids:当前活跃(未提交)的事务ID列表
- min_trx_id:m_id中的最小事务ID
- min_trx_id:系统下一个待分配的事务ID(大于当前所有已分配的ID)
- creator_trx_id:当前事务的ID
可见性规则判断:对于版本链中的某条记录(trx_id为该版本的事务ID):
- 若
trx_id == creator_trx_id
:可见(当前事务修改的记录,自己可见); - 若
trx_id < min_trx_id
:可见(该版本由已提交事务创建); - 若
trx_id > max_trx_id
:不可见(该版本由 “未来” 事务创建); - 若
min_trx_id ≤ trx_id ≤ max_trx_id
:
-
- 若
trx_id
在m_ids
中(事务未提交):不可见; - 若
trx_id
不在m_ids
中(事务已提交):可见。
- 若
https://www.bilibili.com/video/BV1Hr421p7EK/?spm_id_from=333.337.search-card.all.click&vd_source=3abe3667e67749032f72d6f512b2a967
4.什么是索引?索引有哪些分类?
A.索引是一种用于加速查询效率的数据结构
a.优点:显著提升SELECT查询和WHERE条件过滤的效率
b.缺点:会占用额外空间,且会降低INSERT,UPDATE,DELETE性能(因为修改数据时需要同步维护索引结构)。
B.索引的分类
a.按数据结构分:
B+树索引:底层是B+树,是MySQL最常用的索引类型
哈希索引:基于哈希表实现,通过键值对存储,查询时直接计算哈希值定位数据
全文索引:用于对文本内容进行关键字检索,而非单个字段的精确匹配
R树索引:主要用于空间数据类型,支持范围查询
b.按物理存储分:
聚簇索引:索引结构与数据行存储在一起,索引的叶子节点直接包含整行数据
非聚簇索引:索引结构与数据行分开存储,索引的叶子节点存储的是指向数据行的指针(或主键值)
c.按功能逻辑分:
主键索引(唯一且非空),普通索引,唯一索引(索引列的值必须唯一,但允许NULL),联合索引(基于多个列创建的索引),覆盖索引(索引包含查询所需的所有列)
d.特殊索引:
前缀索引(对字符串的前N个字符创建的索引),空间索引(针对空间数据类型的索引)
https://www.bilibili.com/video/BV1tsakezETs/?spm_id_from=333.337.search-card.all.click&vd_source=3abe3667e67749032f72d6f512b2a967
5.什么是智能指针?有哪些种类?
A.智能指针是C++中用于自动管理动态内存的工具,它本质上是封装了原始指针的类模板。
核心作用是:在对象的生命周期结束时,自动调用析构函数释放所指向的内存,从而避免了内存泄漏-这解决了原始指针需要手动delete,容易因遗忘或异常导致内存泄漏的问题。
B.三种智能指针
a.unique_ptr:独占所有权的智能指针
核心特性:同一时间,一个unique_ptr独占指向的内存,不允许拷贝或赋值(避免多个指针管理同一块内存),只能通过移动语义转移所有权。
b.shared_ptr:共享所有权的智能指针
核心特性:多个shared_ptr可以管理同一块内存,内部通过引用计数机制管理-每增加一个指针指向该内存,计数+1,每销毁一个指针,计数-1,当计数为0时,释放该内存。
c.weak_ptr:弱引用的智能指针(解决了shared_ptr的循环引用问题)
核心特性:一种“弱引用”,不拥有内存的所有权,也不增加引用计数,仅用于管擦和shared_ptr管理的内存。它可以shared_ptr创建,用于判断指向的内存是否还存在(通过lock()方法尝试获取shared_ptr)。
https://www.bilibili.com/video/BV1F3DpYaEcA/?spm_id_from=333.337.search-card.all.click&vd_source=3abe3667e67749032f72d6f512b2a967
https://www.bilibili.com/video/BV1zaDGYTEoS?spm_id_from=333.788.player.switch&vd_source=3abe3667e67749032f72d6f512b2a967