360 客户端开发 一面(暑期)

1. 自我介绍

2. 详细讲一下实习工作的内容

3. 为什么一般说 RPC 性能优于 HTTP

答案:严格来说,不能简单地说 RPC 一定优于 HTTP,更准确的说法是很多 RPC 框架在内部服务调用场景下通常比传统 HTTP/1.1 + 文本协议更高效。原因主要在于协议更轻、序列化更紧凑、连接复用更充分、接口定义更明确。很多 RPC 框架会使用 Protobuf 这类二进制序列化格式,相比 JSON 体积更小、解析更快;同时内部调用路径往往不需要那么多通用语义字段,报文开销更低。另外,RPC 框架通常把服务发现、负载均衡、超时控制、重试、熔断、链路追踪这些能力整合进去了,所以在工程上也更适合服务间高频通信。但如果是对外开放接口、浏览器友好性、跨语言和生态兼容,HTTP 仍然非常有优势。

4. Linux 下你一般怎么监控性能指标

答案:先看 CPU、内存、磁盘 IO、网络带宽和上下文切换这几个基础指标。CPU 常用 topmpstatpidstat 看整体利用率和单进程消耗;内存可以用 freevmstatsmem;磁盘 IO 常用 iostatiotop;网络用 sar -n DEVssnetstat;如果怀疑有热点函数或锁竞争,会进一步用 perf 做采样。真正线上排查不会只看机器整体,还要结合进程、线程、连接数、队列积压和日志延迟一起看,不然很容易只看到表象。

代码:

top
mpstat -P ALL 1
pidstat -p 1234 1
vmstat 1
iostat -x 1
sar -n DEV 1
ss -s
perf top -p 1234

5. 怎么定位和排查内存泄漏,常用什么工具

答案:先区分是内存泄漏,还是缓存膨胀、连接堆积、对象池不释放导致的常驻内存增长。如果怀疑是真泄漏,本地调试时可以直接用 AddressSanitizer、Valgrind、LeakSanitizer 这类工具;线上如果不方便上重工具,就先加对象数量、队列长度、连接数、缓存命中率这类指标,看看是不是某类资源持续积压。C++ 服务里常见问题包括 shared_ptr 循环引用、容器只增不减、任务队列消费跟不上、异常路径没释放资源、线程本地对象长期占用等。排查时最好结合时间维度看增长速率,再回溯到最近发布的模块和调用链。

代码:

g++ -fsanitize=address -g main.cpp -o app
./app

valgrind --leak-check=full --show-leak-kinds=all ./app

6. 指针和引用的区别

答案:引用本质上是一个已存在对象的别名,语义上更像“这个名字就是那个对象”;指针本质上是一个变量,里面存的是地址。引用定义时必须初始化,通常不能重新绑定;指针可以为空,也可以在不同时间指向不同对象。从使用上看,引用更适合表达“这个参数一定有效,而且函数内部只是操作原对象”;指针则更适合表达“这个对象可能不存在”或者“需要显式管理地址”。底层实现上编译器可以把引用实现成指针,但语言语义上两者不是一回事。

代码:

#include <iostream>
using namespace std;

int main() {
    int a = 10, b = 20;
    int* p = &a;
    int& r = a;

    p = &b;
    r = b;

    cout << *p << endl;
    cout << r << endl;
    return 0;
}

7. 堆和栈的区别

答案:栈主要存函数调用相关的信息,比如局部变量、返回地址、参数和寄存器现场,分配释放由编译器和调用过程自动完成,速度快,但空间通常比较有限。堆是程序运行时动态申请的大块内存区域,生命周期由程序员或运行时决定,灵活性更强,但分配释放成本更高,也更容易产生碎片和泄漏。如果面试官继续问,一般还会追栈溢出、堆碎片、内存分配器和线程栈空间这些问题。

8. static 关键字的作用

答案:static 修饰局部变量时,表示它只初始化一次,但作用域还在原来的代码块里;修饰全局变量或函数时,表示它们只在当前编译单元可见;修饰类成员变量时,表示它属于整个类而不是某个对象;修饰类成员函数时,表示这个函数没有 this 指针。这题本身不难,但延伸出去很容易问到静态局部变量线程安全、静态初始化顺序和单例实现。

代码:

#include <iostream>
using namespace std;

class A {
public:
    static int cnt;
    A() { ++cnt; }
};

int A::cnt = 0;

int main() {
    A a, b;
    cout << A::cnt << endl;
    return 0;
}

9. 死锁的必要条件是什么

答案:死锁一般满足四个必要条件:互斥、请求与保持、不可剥夺、循环等待。互斥指资源一次只能被一个执行单元占用;请求与保持指已经持有部分资源的线程还在继续请求新资源;不可剥夺指资源不能被强制拿走;循环等待指多个线程之间形成了资源依赖环。避免死锁最常见的方法是统一加锁顺序、尽量缩小锁粒度、使用 try_lock 或带超时的锁,以及在设计阶段避免多把锁交叉持有。

10. 进程和线程的区别,线程奔溃后在进程视角会发生什么

答案:进程是资源分配的基本单位,线程是

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

C++ 常考面试题总结 文章被收录于专栏

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

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

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