网易雷火 游戏服务器-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++ 常考面试题总结 文章被收录于专栏

本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

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