今天分享的是粉丝投稿的在腾讯的最新面经,问的都是一些高质量的问题,看看你能答上来几个:
1. Proactor和Reactor模式的区别?
核心区别:事件处理流程不同
- Reactor:基于同步I/O,主线程监听事件就绪后,由工作线程执行实际I/O操作(读/写)和业务处理。典型代表:Linux epoll
- Proactor:基于异步I/O,主线程直接处理I/O操作完成后的事件通知,工作线程仅处理业务逻辑。典型代表:Windows IOCP
2. 栈和堆的内存管理差异?
栈 | 堆 | |
---|---|---|
分配方式 | 编译器自动分配/释放 | GC自动管理 |
内存碎片 | 无 | 可能产生碎片 |
访问速度 | 快(CPU缓存友好) | 较慢(需寻址) |
逃逸分析 | 函数内部分配 | 跨函数共享时逃逸 |
3. Slice的底层存储结构?
type slice struct {
array unsafe.Pointer // 指向底层数组
len int
cap int
}
- 存储位置:slice头结构可能在栈或堆,底层数组始终在堆
- 关键特性:自动扩容(cap不足时2倍增长),共享底层数组
4. 说一下grpc和http2.0
gRPC
- 简介:是Google开发的高性能开源RPC框架,能让客户端像调用本地方法一样调用远程服务器上的方法,方便构建分布式系统和微服务架构。
特点
- 以高效、紧凑的ProtoBuf作为默认数据序列化格式。
- 支持Java、C++、Python、Go等多种编程语言,便于异构环境集成。
- 支持双向流通信,客户端和服务端可同时收发多个消息,提升通信灵活性与效率。
- 应用场景:常用于微服务架构中微服务间通信、云原生应用以及移动应用与后端服务通信等场景。
HTTP/2.0
- 简介:是HTTP协议的第二个主要版本,对HTTP/1.x进行了重大升级,以提升网络传输效率和性能。
特点
- 采用二进制分帧传输数据,数据解析和处理更高效,传输更可靠。
- 支持多路复用,可在同一个连接上同时发送多个请求和响应,解决了队头阻塞问题,提高连接利用率,减少延迟。
- 运用HPACK算法对头部进行压缩,降低了头部数据传输量,提高传输效率。
- 应用场景:广泛应用于Web应用、CDN内容分发等需要高效网络传输的场景,能优化网页加载速度,提升用户体验。
5. Protobuf是什么
基本概念
是一种与语言、平台无关的序列化方式,能把结构化数据转成字节流传输或存储,也可从字节流恢复数据,类似XML和JSON,但有独特优势。
核心特点
- 高效:采用二进制编码,比XML和JSON等文本格式空间占用小、处理速度快,可减少带宽和存储成本,提升数据处理效率。
- 多语言支持:支持Java、C++、Python等多种编程语言,不同语言系统间能方便地用它交换数据。
- 可扩展:定义数据结构时能添加新字段,旧代码解析含新字段数据时会忽略新字段,保证向前兼容性,便于数据结构升级。
- 强类型:定义数据结构时要明确字段数据类型,有助于编译时发现错误,提高程序稳定性和可靠性,也让数据处理更高效准确。
工作原理
- 先在.proto文件定义消息形式的数据结构。
- 用Protobuf编译器生成特定编程语言代码,包含序列化、反序列化方法及操作字段的接口。
- 发送端将数据填进消息对象,序列化转成字节流发送或存储;接收端读取字节流,反序列化恢复成消息对象来处理数据。
6. Goroutine与线程的核心区别?
Goroutine | OS线程 | |
---|---|---|
内存开销 | 2KB初始栈 | 1-2MB栈空间 |
创建速度 | 0.3μs | 10μs |
调度方式 | 用户态GMP调度 | 内核态调度 |
切换成本 | 120ns | 1-2μs |
7. Go的并发原语对比JS Promise?
Go特性:
- goroutine + channel实现CSP模型
- sync.WaitGroup控制并发等待
- context实现超时控制
对比差异: - 无链式调用语法
- 通过select实现多路复用
- 原生支持并发安全Map(sync.Map)
8. 线程安全的LRU实现方案?
type SafeLRU struct {
sync.RWMutex
cache *lru.Cache
}
func (s *SafeLRU) Get(key string) interface{} {
s.RLock()
defer s.RUnlock()
return s.cache.Get(key)
}
// 使用hashicorp/golang-lru实现基础LRU
优化方案:
- 分片锁(Sharded Lock)
- 原子操作替代锁(适用于计数器场景)
- 无锁队列(sync/atomic实现)
9. sync.Pool的使用场景?
- 缓存临时对象,减少GC压力
- 网络连接池复用
- 大内存块复用
注意要点:
- 获取的对象可能残留旧数据
- 不适合存储有状态资源
- GC时会清空Pool
10. TCP粘包解决方案?
- 定长分包:按固定长度分包数据,接收方依此读取,适用于数据长度固定的场景,如固定格式的协议数据。
- 特殊字符分隔:在包尾加特殊字符或序列作分隔符,接收方据此判断包边界,适用于数据不包含分隔符的情况,如文本协议。
- 消息头记录长度:在包头部设字段记录包长,接收方先读长度字段,再按此长度读取数据,适用于数据长度不固定的情况,通用性强。
- 使用应用层协议:在应用层定义协议,规定数据包格式等,通过解析协议处理粘包,如HTTP协议,适用于需复杂数据处理和交互的场景。
- 基于框架或库:利用Netty、Twisted等成熟框架或库处理粘包,它们有内置处理机制,适用于使用相应框架开发的项目,可简化开发。
11. 值传递 vs 指针传递?
值传递 | 指针传递 | |
---|---|---|
内存分配 | 栈拷贝 | 传递指针地址 |
修改影响 | 不影响原值 | 影响原值 |
适用场景 | 小结构体(<64B) | 大结构体或需修改 |
12. 分片上传的实现?
典型方案:
- 前端计算文件hash(spark-md5)
- 服务端预检分片状态
- 并行上传分片(每个分片单独PUT请求)
- 服务端合并分片
Go实现要点: - 使用sync.Pool管理分片缓冲区
- 采用文件锁保证合并安全
- 支持断点续传(记录分片状态)
13. Slice与List的差异?
Slice | List(container/list) | |
---|---|---|
内存布局 | 连续内存 | 双向链表节点 |
随机访问 | O(1) | O(n) |
插入删除 | O(n) | O(1) |
缓存友好 | 是 | 否 |
14. GC调优策略?
- 减少堆内存分配(复用对象)
- 控制对象生命周期(及时设为nil)
- 调整GOGC参数(默认100)
- 使用pprof分析内存分配
- 避免大内存对象(拆分slice)
15. Context的核心作用?
- 传递请求上下文(traceID等)
- 超时控制(WithTimeout)
- 取消传播(WithCancel)
- 值传递(WithValue)
正确用法:
- 作为函数第一个参数传递
- 线程安全,应传递副本而非引用
值传递只用于请求域数据
以上就是面经的全部内容,希望对你有帮助。
欢迎关注 ❤
我们搞了一个免费的面试真题共享群,互通有无,一起刷题进步。
没准能让你能刷到自己意向公司的最新面试题呢。
感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:sf面试群。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。