Golang语言面试题 - 常见题
下面会给出网上收集的字节系 Golang 语言常见的面试题,按照热度排序哦
简述 slice 的底层原理,slice 和数组的区别是什么?
slice 是数组的引用,额外包括两个字段,长度 len 和容量 cap
slice支持扩容,本质上是再申请一块内存,将老数据复制过去,更新引用地址
简单介绍 GMP 模型以及该模型的优点 困难
简述 Golang 垃圾回收的机制 中等
Golang 采用的垃圾回收机制是三色标记法,分为白色(未标记)、灰色(标记中)、黑色(已标记)。
回收流程为:
1. STW,从根节点出发,将根节点标记为黑色,将能达到的所有节点标记为灰色,然后将所有能达到的子节点加入队列
2. 并发遍历队列中的节点,标记为黑色,且继续寻找其子节点标记为灰色并加入队列
3. 直到队列中所有可达节点均遍历完毕,那么剩下的白色节点就是不可达的节点,可以回收掉
在实际使用过程中,如果在标记过程中,节点指针被用户操作改变,可能会标记失败被错误的清除掉,因此 Go 又引入了写屏障
一次完整的 GC 分为四个阶段:
- 标记准备(Mark Setup,需 STW),打开写屏障(Write Barrier),开启辅助 GC (mutator assist),统计 root 对象的任务数量
- 使用三色标记法标记(Marking, 并发)
- 标记结束(Mark Termination,需 STW),关闭写屏障。
- 清理(Sweeping, 并发)
GC 调优
- 减少使用string类型中的 ‘+’(此种方式每次拼接都会申请一段新的内存空间),推荐使用 strings.Builder (类似切片的扩容机制)
- 小对象复用,尽量减少声明局部变量,小对象可以加入结构体来复用,方便 GC 扫描
协程与进程,线程的区别是什么?协程有什么优势?
Goroutines是可以同时运行的函数与方法。Goroutines 可以被认为是轻量级的线程。 与线程相比,创建 Goroutine 的开销很小。 Go应用程序同时运行数千个 Goroutine 是非常常见的做法。
- 进程: 进程是具有一定独立功能的程序,进程是系统资源分配和调度的最小单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
- 线程: 线程是进程的一个实体,线程是内核态,而且是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
- 协程: 协程是一种用户态的轻量级线程,协程的调度完全是由用户来控制的。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
简述 defer 的执行顺序 中等
1.
Golang 有哪些优缺点、错误处理有什么优缺点?
优点:
- 简洁、高效、安全
- 并发处理能力强
- 静态类型和编译型
- 丰富的标准库
- 跨平台和可移植性
- 强大的性能
- 垃圾回收机制
劣势: - 泛型编程支持不足
- 错误处理方式可能不同
采用错误返回方式,错误是一种内置类型,可以使用 error 类型来定义。而异常(panic)也可以通过 recover() 函数转换为 error来处理。优点是简单直观,一般与主体程序分离。可能的缺点是,需要在调用链中做好收集和处理,如果漏处理可能会有问题。
1 | defer func() { |
两次 GC 周期重叠会引发什么问题,GC 触发机制是什么样的? 简单
Golang 的协程通信方式有哪些? 中等
channel 分为有缓冲和无缓冲,有缓冲的满不能存空不能取,都会阻塞;无缓冲的不存就不能取,阻塞
sync.waitgroup 控制协程完成时间,多用于等待一批协程完成
context 可以传值 context.withvalue;控制多个协程的生命周期,超时控制,取消信号等
△ 4次
简述 Golang 的伪抢占式调度 中等
△ 4次
什么是 goroutine 泄漏 简单
△ 4次
groutinue 什么时候会被挂起? 简单