网易雷火 游戏服务器-C++ 二面
1. 自我介绍
2. 目前有 offer 吗?
3. 聊了聊实习
4. Lua 的 GC 底层怎么做的?怎么回收的?虚拟机层面了解吗?
Lua 的 GC 核心思想是可达性分析。经典实现是增量标记清除,较新的版本还支持分代 GC。 简单说,Lua 会从一批根对象出发,比如全局表、当前调用栈上的局部变量、闭包、注册表等,去遍历所有还能访问到的对象,把它们标记为存活。没有被标记到的对象,后面就会被回收。
Lua 采用增量方式的原因是,如果一次性做完整 GC,停顿会比较明显,所以它会把回收过程拆成很多小步,在 VM 执行过程中逐步推进。 从虚拟机角度看,GC 和 Lua 的对象模型、栈帧、闭包、table 结构都强相关,像 TValue、GCObject、lua_State 这些结构都会参与扫描和状态推进。
代码:
void GCStep() {
switch (state) {
case GCSpropagate:
markReachableObject();
break;
case GCSatomic:
remarkRoots();
break;
case GCSsweep:
sweepUnmarkedObjects();
break;
}
}
5. Lua 的 table 源码看过吗?说说 table
答案: Lua 的 table 是最核心的数据结构之一,它不是单纯的哈希表,而是数组区 + 哈希区的混合结构。 这样设计的原因是 Lua 里的 table 同时承担了很多角色:
- 数组
- 字典
- 对象
- 模块
- 元表载体
如果全部只用普通哈希表,很多连续整数下标访问会浪费空间,也不够高效。 所以 Lua 会把连续正整数 key 尽量放到数组区,其他 key 放到哈希区。插入元素后,如果 key 分布发生变化,还会触发重哈希,重新平衡数组区和哈希区的比例。
代码:
typedef struct Table {
TValue *array;
Node *node;
unsigned int alimit;
unsigned int lsizenode;
} Table;
6. Lua 虚拟机的执行模型大致是什么?栈帧是怎么组织的?
Lua VM 本质上是一个解释执行字节码的虚拟机,偏寄存器风格。这里说的“寄存器”并不是 CPU 里的真寄存器,而是函数调用栈帧中的槽位。 Lua 源码会先编译成字节码,运行时虚拟机逐条取指执行,操作的数据大多存在当前函数的栈帧里。
几个关键结构通常要知道:
- lua_State:线程状态、栈、GC、调用信息
- CallInfo:调用帧
- Proto:函数原型和字节码
- TValue:统一表示 Lua 值
7. C++11 里右值引用、移动语义、完美转发分别是什么?它们怎么配合减少拷贝?
右值引用 T&& 允许你绑定到临时对象,表达“这个对象的资源可以被搬走”。 移动语义的核心价值是避免不必要的深拷贝,尤其是像 string、vector 这种内部持有堆内存的对象,移动时直接接管资源比重新拷贝便宜很多。 完美转发解决的是模板场景里参数值类别丢失的问题,通过 std::forward<T>(arg) 可以把左值继续转成左值,把右值继续转成右值。
代码:
#include <iostream>
#include <utility>
#include <vector>
class Buffer {
public:
Buffer(size_t n = 0) : data_(n, 0) {}
Buffer(const Buffer& other) : data_(other.data_) {
std::cout << "copy\n";
}
Buffer(Buffer&& other) noexcept : data_(std::move(other.data_)) {
std::cout << "move\n";
}
private:
std::vector<int> data_;
};
void use(const Buffer&) { std::cout << "use lvalue\n"; }
void use(Buffer&&) { std::cout << "use rvalue\n"; }
template <class T>
void wrapper(T&& x) {
use(std::forward<T>(x));
}
8. Lua 里的 table 和 C++ 容器有什么区别?
严格来说,Lua 并没有像 C++ STL 那样一套强类型容器体系。 Lua 里大量数据结构都是靠 table 去模拟的,比如:
- 数组
- list
- map
- object
而 C++ 的容器设计更强调“不同场景用不同结构”,例如:
- vector 强调连续存储和随机访问
- list 强调节点稳定和插删
- map/unordered_map 强调键值查找
两者最本质的区别在于:
- Lua 更强调灵活性和动态性
- C++ 更强调类型约束和性能可预测性
所以脚本层常见做法是先用 table 把功能表达出来,而 C++ 更适合对访问模式和复杂度做精确控制。
9. C++ List 和 Vector 的区别
答案:
vector 的底层是连续内存,优点是:
- 支持随机访问
- 遍历快
- cache 友好
- 内存开销相对小
list 的底层是双向链表,优点是:
- 已知位置时插入删除方便
- 节点地址稳定
- 不会像 vector 那样因为扩容搬迁整体元素
但现代工程里,大多数场景其实更倾向 vector。因为 CPU 对连续内存的友好程度非常高,list 虽然理论上中间插删方便,但遍历和查找常常很吃亏。 如果不是明确依赖“中间频繁插删 + 节点稳定”,一般优先考虑 vector。
代码:
#include <vector>
#include <list>
std::vector<int> v = {
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

查看16道真题和解析